> ## Documentation Index
> Fetch the complete documentation index at: https://xum.cdr.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Sandbox

> Run local agent commands in a macOS sandbox that keeps writes in the workspace and credentials out of reach

An agent runs shell commands with your user's rights. A wrong command can change files outside the workspace, read your keys, or send data to any host. The agent sandbox limits what agent commands can do. It is off by default.

The sandbox works only on macOS. It covers Local and Worktree workspaces. SSH, Coder, Docker, and Devcontainer workspaces are not covered: their commands run on another machine or in a container.

## Turn on the sandbox

In **Settings → Agents → Agent sandbox**, turn on **Run agent commands in a sandbox**. Commands that start after that run in the sandbox.

On another operating system, or on a Mac without `/usr/bin/sandbox-exec`, the section shows why the sandbox is not available and you cannot turn it on. If the setting is already on there (for example in a `config.json` copied from a Mac), the section says so, and you can only turn it off: with the switch, or with **Global** or **Off** for a project that is **On**. Until then:

* On another operating system, commands run without the sandbox.
* On a Mac without `sandbox-exec`, the commands that the sandbox covers fail. Xum does not run them without the sandbox that you turned on, unless you approve one command with **Run outside once** (see [Approve one command outside the sandbox](#approve-one-command-outside-the-sandbox)).

To use another setting for one project, select the project in **Project** and click:

* **Global**: the project follows the switch.
* **On**: the sandbox is on for this project, also when the switch is off.
* **Off**: the sandbox is off for this project, also when the switch is on.

A sub-project has the setting of its parent project, because its workspaces work in the parent's checkout. **Project** lists only parent projects, and Xum ignores an `agentSandbox` setting of a sub-project in `config.json`.

A multi-project workspace uses the strictest setting of its projects, because its commands can change each checkout. The sandbox is on when it is on for one of the projects. Commands can then use only the network mode, hosts, and paths that the sandbox of each project with the sandbox on allows. Host names match in any case. Paths match where they really are, so a folder that two projects name through different symlinks stays open. When the sandbox of one of the projects fails to start, commands of the workspace fail to start too.

Agent tools cannot change the sandbox setting. While the setting is on, globally or for one project, the agent's config tool cannot write Xum's config or providers at all, also on another operating system, where commands run without the sandbox.

## What commands can write

Commands in the sandbox can write only to these folders:

* The workspace and its scratch folder.
* Temp folders: `/private/tmp` and `$TMPDIR`. The sandbox sets `$TMPDIR` to the system temp folder, also when a secret sets it to another folder.
* Tool caches: `~/.npm`, `~/.cache`, `~/.cargo/registry`, `~/.cargo/git`, `~/go/pkg/mod`, `~/.gradle/caches`, `~/.m2/repository`, `~/Library/pnpm/store`, `~/.pnpm-store`, `~/Library/Caches/go-build`, `~/Library/Caches/pip`, `~/Library/Caches/Yarn`, `~/Library/Caches/ms-playwright`, `~/Library/Caches/node-gyp`, and `~/Library/Developer/Xcode/DerivedData`.
* For a worktree workspace, the `.git` folder of the main checkout, so that commits work.

A tool cache or `$TMPDIR` that is a symlink stays closed, because a command could replace it with a link to another folder. Add the folder that it links to to `extraWritePaths`.

If Xum's home folder (`~/.xum`, or `XUM_ROOT`) is inside a folder that commands can write, such as a temp folder, a tool cache or an `extraWritePaths` entry, commands in the sandbox fail to start, because a command could change Xum's own settings there. They also fail to start when the workspace or another folder that they can write is inside `~/.config/git` or a global skill or plugin folder, such as a plugin checkout in `~/.agents/plugins`, or inside a folder that an entry of a global skill or plugin folder links to (`~/.agents/plugins/demo` linking to the workspace), because Xum runs the code there outside the sandbox. They also fail to start when the workspace, or an `extraWritePaths` entry, is reached through a link inside another folder that commands can write, such as a checkout in `/tmp` that a command replaced with a link to `~/.ssh`, and when the scratch folder (`$XUM_SCRATCH_DIR`) is a link. The same applies to Xum's home folder, the global git config (also where `XDG_CONFIG_HOME`, `GIT_CONFIG_GLOBAL` or `GIT_CONFIG_SYSTEM` moves it), `~/.bunfig.toml`, `~/.ssh/config`, the global instruction files, the npx, uv and Bun caches below (also where Xum's environment or the project's secrets move them), the credential and config files below where a variable names them (such as npm's `userconfig`), the global skill and plugin folders and the links in them and in the global agent folder (`~/.xum/agents`), the git folders that a `.git` or `commondir` file names, the links in your home folder, the files that git and ssh config include, and the `.git` of the workspace: Xum, git, ssh, `npx`, `uvx`, `bunx` and your shell use them outside the sandbox through that link, which a command could replace. So a workspace whose `.git` is a symlink does not work in the sandbox. They also fail to start when Xum's environment or the project's secrets set one of the variables below that move the global git config, a tool cache or a credential file to a relative path, such as `GIT_CONFIG_GLOBAL=my.gitconfig`, because git, npm, uv and Bun resolve it from the folder they run in, and Xum runs its own git in the workspace. They also fail to start when the workspace, the scratch folder or another folder that they can read is inside one of the hidden credential paths below, such as Xum's `askpass` folder, because the sandbox could not hide it there. They also fail to start when the project's secrets set `HOME` to a folder other than your home folder, because git, npm and the MCP servers that Xum starts outside the sandbox with those secrets read their settings there. They also fail to start when the `commondir` file in the git folder of the workspace's worktree names a folder other than the main checkout's `.git`, because git outside the sandbox takes the config and hooks of the folder that it names.

Some files stay read-only, also inside the workspace, where they link to and in any letter case, because a command could use them to run code later outside the sandbox:

* `.git/hooks`, `.git/config`, `.git/config.worktree`, `.git/commondir`, `.git/modules` (the git folders of submodules), and `.git` itself where it is not a folder: the `.git` file of a worktree, or a `.git` that does not exist yet, so `git init` fails in the sandbox. In the `.git` folder of the main checkout, in the git folder that a `.git` file names (`git init --separate-git-dir`), and in the folder that the `commondir` file of either names, the same paths, and `config.worktree`, `modules` and `commondir` in the folder of each worktree. Also the files that the hooks in these `hooks` folders link to, such as `scripts/post-checkout` in the workspace for a `.git/hooks/post-checkout` link.
* `.xum/mcp.jsonc`, `.mux/mcp.jsonc`, `.xum/mcp.local.jsonc`, `.mux/mcp.local.jsonc`, `.xum/mcp.local.json`, `.mux/mcp.local.json`, `.mcp.json`, `.xum/plugins`, `.mux/plugins`, and `.agents/plugins`.
* `.xum/tool_env` and `.mux/tool_env`, which bash runs before each command in a trusted project, also before a command that you let run outside the sandbox.
* `~/.npm/_npx` (or where `npm_config_cache` moves the npm cache), the uv cache (`~/.cache/uv`, or where `XDG_CACHE_HOME` or `UV_CACHE_DIR` moves it), the Bun install and transpiler caches (`~/.bun/install/cache` and `~/Library/Caches/bun`, or where `BUN_INSTALL_CACHE_DIR`, `BUN_INSTALL`, `BUN_RUNTIME_TRANSPILER_CACHE_PATH` or `XDG_CACHE_HOME` moves them), and the `bunx-<uid>-*` and `.bunx-<uid>` folders in the temp folders. `npx`, `uvx` and `bunx` keep what they run there, also for MCP servers that start outside the sandbox. Commands in the sandbox can still run what is there. uv and Bun in the sandbox use caches of their own in `$TMPDIR`.
* `.vscode`, `.idea`, `.envrc`, and `.gitmodules`.
* `.devcontainer.json` and `.devcontainer`, because `devcontainer up` runs their `initializeCommand` on your Mac.
* Where links in your home folder point into a folder that commands can write (a dotfiles checkout): the dot entries of the home folder (such as `~/.gitconfig`, `~/.zshrc` or `~/.npmrc`), the entries of `~/.config`, `~/.ssh` (such as `~/.ssh/config`), `~/.claude` and Xum's home folder (such as a global `CLAUDE.md` or `AGENTS.md`), and the global skill and plugin folders, because git, ssh, `npx`, `bunx` and your shell outside the sandbox run what they name, and Xum reads the global instruction files into its prompt. A link to the whole folder that commands can write, or to a folder above it, does not make that folder read-only.
* Where an entry of a global skill, plugin or agent folder links into a folder that commands can write (a plugin linked to its checkout), the folder that it links to. Links deeper inside the entry are not followed.
* The global and system git config, also where Xum's environment or the project's secrets move them (`XDG_CONFIG_HOME`, `GIT_CONFIG_GLOBAL` or `GIT_CONFIG_SYSTEM`), where they are in a folder that commands can write. The system config is `/etc/gitconfig`, the `etc/gitconfig` of Homebrew or MacPorts, or the defaults that Apple's git ships with in the Command Line Tools or in `/Applications/Xcode.app`; a git with its system config elsewhere is not covered.
* `~/.ssh/config`, where it is in a folder that commands can write (an `extraWritePaths` entry for `~/.ssh`), because ssh runs its `ProxyCommand` for Xum's own `git fetch` outside the sandbox.
* The global instruction files (`~/.claude/CLAUDE.md`, and `AGENTS.md`, `AGENT.md`, `CLAUDE.md` and `AGENTS.local.md` in Xum's home folder), where they are in a folder that commands can write, because Xum reads them into the prompt of every workspace, also one without the sandbox.
* The files that git config includes (`include.path` and `includeIf` entries, in the global and system git config, in the config of the repository that the workspace is in, also when the workspace is a folder inside it, and of its submodules, and in the files they include), and the files that `~/.ssh/config` and the system `/etc/ssh/ssh_config` include (`Include`), where they are in a folder that commands can write. For an `Include` with a wildcard in its last name, every name in that folder that starts like the pattern stays read-only, and so does where a link among them points. Commands fail to start when an include is in a form the sandbox does not read: a partly quoted or escaped git include path, `~user/` or `%(prefix)/`, an `Include` with a token, a variable or a wildcard in a folder name, or an `Include` argument with a backslash or quoted in part. They also fail to start when one of these config files is larger than 1 MiB.

Commands also fail to start when one of these files, or a git or ssh config file that the sandbox reads, has more than one hard link, because a write through the other name changes the same file and the sandbox cannot keep that name read-only. Replace the hard link with a copy or a symlink.

Files inside a read-only folder, such as `.xum/plugins` or `.git/hooks`, are not checked for hard links. A command in the sandbox cannot make a hard link to them, but a program outside the sandbox can. For example, pnpm with `package-import-method=hardlink` links the files in a plugin's `node_modules` to its store, which commands can write, so a command can change them there.

## What commands can read

Commands in the sandbox can read:

* The workspace and the folders they can write.
* System files and folders outside `/Users`, `/Volumes` and your home folder.
* Toolchains and tool settings in your home folder: `~/.gitconfig`, `~/.config/git`, `~/.bun`, `~/.cargo`, `~/.rustup`, `~/go`, `~/Library/Application Support/go`, `~/.nvm`, `~/.volta`, `~/.pyenv`, `~/.asdf`, `~/.local/share/mise`, `~/.local/share/uv`, and `~/.sdkman`. A link in a folder that commands can write is not followed from one of them, because a command could point it at `~/.ssh`.
* The global git config, also where Xum's environment or the project's secrets move it.
* The global skill and plugin folders.
* The folders in your `PATH` that are in your home folder. Only the folder itself opens: if a tool in it needs files next to it, add them to `extraReadPaths`. A `PATH` folder that a symlink in a writable folder links to stays closed.
* For a [tool hook](https://xum.cdr.dev/hooks/tools.md), the payload files that `XUM_TOOL_INPUT_PATH` and `XUM_TOOL_RESULT_PATH` name.
* For a [Cursor plugin hook](https://xum.cdr.dev/hooks/plugins.md), the chat log that `transcript_path` names. The hook starts in the workspace, so the plugin folder stays read-only, and then changes to the plugin folder.

Everything else in `/Users`, `/Volumes`, your home folder (also when it is not in `/Users`) and Xum's home folder (also when `XUM_ROOT` moves it outside your home folder) is hidden. Some credential files stay hidden and read-only, also inside folders that are open and when you add them to `extraReadPaths` or `extraWritePaths`. Where a variable moves one, the sandbox reads it from Xum's environment and from the project's secrets:

* `~/.cargo/credentials` and `~/.cargo/credentials.toml` (or in `CARGO_HOME`).
* `~/.config/git/credentials` (or where `XDG_CONFIG_HOME` moves it).
* `~/.cache/huggingface/token`, and `stored_tokens` next to it, where `hf auth login` keeps every token it saved (or where `XDG_CACHE_HOME`, `HF_HOME` or `HF_TOKEN_PATH` moves them).
* `~/.local/share/uv/credentials` (or where `XDG_DATA_HOME` or `UV_CREDENTIALS_DIR` moves it), where `uv auth login` keeps its tokens, so uv in the sandbox cannot use them.
* `~/Library/Application Support/go/env` (or where `GOENV` moves it), where `go env -w` keeps its settings, which can hold a password in `GOPROXY`. Go in the sandbox runs without them, so set what a build needs, such as `GOPRIVATE` or `GOFLAGS`, in the environment instead.
* The npm user and global config where a variable moves them, because they can hold registry tokens: `npm_config_userconfig`, `npm_config_globalconfig`, and `npm_config_prefix` or `PREFIX`, which move the global config to `<prefix>/etc/npmrc`. npm reads `npm_config_` in any case. Without them, `~/.npmrc` is only closed (see below). The global config of a Node in an open folder, such as `~/.nvm/versions/node/<version>/etc/npmrc`, stays open, so keep registry tokens in `~/.npmrc`.
* The pip config that `PIP_CONFIG_FILE` names. pip in the sandbox runs without it.
* The `gradle.properties` in the folder that `GRADLE_USER_HOME` names, because it can hold repository credentials. Gradle in the sandbox runs without it.
* The `config.json` in the folder that `DOCKER_CONFIG` names, because it can hold registry logins and proxy passwords. `~/.docker` is not open either.
* The AWS files that `AWS_SHARED_CREDENTIALS_FILE` and `AWS_CONFIG_FILE` name (also with a leading `~/`), the key files that `GOOGLE_APPLICATION_CREDENTIALS` and `AZURE_CLIENT_CERTIFICATE_PATH` name, the folders that `CLOUDSDK_CONFIG` and `AZURE_CONFIG_DIR` name, the `hosts.yml` in the folder that `GH_CONFIG_DIR` names, and each file that `KUBECONFIG` lists, because they hold cloud keys and tokens. Their default folders in your home folder are not open either.
* The `.netrc` that `NETRC` names, because Python and Go read logins from it.
* The files where more tools keep tokens, where a variable moves them: the Terraform CLI config that `TF_CLI_CONFIG_FILE` or `TERRAFORM_CONFIG` names, `credentials.json` in `PULUMI_HOME`, the configs that `RCLONE_CONFIG`, `BOTO_CONFIG`, `OCI_CLI_CONFIG_FILE`, `DATABRICKS_CONFIG_FILE`, `HUB_CONFIG` and `HELM_REGISTRY_CONFIG` name, `auth.json` in `COMPOSER_HOME`, `config.yml` in `GLAB_CONFIG_DIR`, `kaggle.json` in `KAGGLE_CONFIG_DIR`, and `key.pem` in `DOCKER_CERT_PATH`.
* The file that a variable names when its name says it holds a secret: the name ends in `TOKEN`, `CRED`, `CREDS`, `CREDENTIAL`, `CREDENTIALS`, `PASS`, `PASSWORD`, `SECRET`, `SECRETS`, `KEY` or `AUTH`, then `_FILE`, `FILE`, `_PATH` or `PATH`, then an optional `_OVERRIDE`. Examples are `AWS_WEB_IDENTITY_TOKEN_FILE`, `CLOUDSDK_AUTH_ACCESS_TOKEN_FILE`, `CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE`, `AZURE_FEDERATED_TOKEN_FILE`, `PGPASSFILE`, `SOPS_AGE_KEY_FILE` and `POSTGRES_PASSWORD_FILE`. Only a value that is an absolute path or starts with `~/` counts.
* Xum's `server.lock`, `providers.jsonc`, `secrets.json`, `mcp-oauth.json`, and `config.json`, and its `askpass` folder, where your answers to SSH prompts pass. `xum run` and `xum workflow` keep their copy of `config.json`, `providers.jsonc` and `secrets.json` in a temp folder, and that copy is hidden too, with the files whose names start with one of these names and a dot, such as the temp file that Xum writes before it replaces one.

Commands fail to start when one of these files has more than one hard link, because the sandbox hides and protects names, not files, so the other name would open it.

These files are not open, because they can hold tokens: `~/.npmrc`, `~/.bunfig.toml`, `~/.pypirc`, `~/.gradle/gradle.properties`, and `~/.m2/settings.xml`. If a build needs one of them, add it to `extraReadPaths` (see [Open more paths](#open-more-paths)).

Xum reads the instruction files of the workspace, such as `AGENTS.md`, its agent definitions in `.xum/agents` and its skills in `.xum/skills` or `.agents/skills` as a command in the sandbox would, with the project's secrets, because a command could replace one with a link to a key or to a file that a secret names. An instruction file that links to a hidden file loads as empty. An agent definition or skill that links to one does not load, so the agent or skill of that name in Xum's home folder, or the built-in one, loads in its place. `agent_skill_read_file` does not read a hidden file from a workspace skill, `agent_skill_write` and `agent_skill_delete` change a file of a workspace skill only where a command in the sandbox could, and `mux_agents_read` and `mux_agents_write` read and write the workspace's `AGENTS.md` only where a command in the sandbox could. `workflow_run` runs a workflow script of the workspace or of a workspace skill, also one that another workflow starts, only where a command in the sandbox could read it. To load a file that links into your home folder, add its target to `extraReadPaths`. When Xum proposes the plan of plan mode, it reads the plan file the same way. Commands cannot change the plan file, because it is in Xum's home folder.

Unix sockets are closed in all network modes, for example the sockets of Docker, `ssh-agent`, 1Password, and `gpg-agent`. The macOS keychain is closed too, and `open` cannot start an app, which would run outside the sandbox.

## Network

Commands in the sandbox reach the network through a local proxy. In **Network**, select one mode:

* **Allowed hosts only** (the default): commands can reach only the hosts in the list. The default list has 16 package registries and git hosts: `registry.npmjs.org`, `registry.yarnpkg.com`, `pypi.org`, `files.pythonhosted.org`, `crates.io`, `index.crates.io`, `static.crates.io`, `proxy.golang.org`, `sum.golang.org`, `github.com`, `api.github.com`, `codeload.github.com`, `objects.githubusercontent.com`, `raw.githubusercontent.com`, `gitlab.com`, and `bitbucket.org`.
* **Any host**: commands can reach all hosts.
* **Loopback only**: commands can reach only `localhost`.

To change the list, click **Edit hosts**, enter one host on each line, and click **Save hosts**. To go back to the default list, click **Edit hosts**, then **Use defaults**. A list that you edited does not change when a later version of Xum changes the default list.

In all modes, loopback stays open, so dev servers and their tests work. The proxy refuses an allowed host name that resolves to a private address range.

In all modes, a command can also listen on every network interface, not only on loopback, so other computers on your network can connect to a dev server that listens on `0.0.0.0` or `::`. The macOS sandbox cannot limit a listener to loopback: it treats a listener on every interface as a loopback listener.

## Open more paths

To let commands write or read more paths, edit `~/.xum/config.json`:

```jsonc theme={null}
{
  "agentSandbox": {
    "enabled": true,
    "network": "allowlist",
    // Folders that commands can write and read.
    "extraWritePaths": ["~/.gradle"],
    // Files and folders that commands can read.
    "extraReadPaths": ["~/.npmrc"],
  },
}
```

A path can start with `~/`. A project can have its own `agentSandbox` with the same fields, in its entry in `projects`. Each field that the project sets replaces the global field. For example, a project `extraReadPaths` replaces the global `extraReadPaths`, it does not add to it. A repository cannot set the sandbox. The agent's config tool cannot change `agentSandbox`, and while the sandbox is on, it cannot write Xum's config or providers at all. In a system workspace that the sandbox covers, the agent's skill and AGENTS.md tools cannot change the global skills or Xum's global `AGENTS.md`, because every workspace loads them. In any workspace that the sandbox covers, the memory tool cannot change global memory, because every workspace with memory loads its index. For the same reasons, the refinement rollback tool cannot undo a change to global memory or a global skill in a workspace that the sandbox covers.

Xum ignores a field that is not valid and keeps the valid fields, so a broken field next to `"enabled": true` does not turn the sandbox off. An `agentSandbox` value that is not an object is ignored as a whole. Xum shows no message for this, and the next save from Settings writes the value without the broken fields.

## Approve one command outside the sandbox

When the sandbox blocks a command, the bash card shows a **Sandbox** badge and a line that names what the sandbox blocked. The agent can then ask to run the command once outside the sandbox, with a reason.

The request shows as a card with the command and the reason. Click **Run outside once** to run that one call without the sandbox, or **Deny** to refuse it. The keyboard shortcuts answer the newest card (see [Keyboard shortcuts](https://xum.cdr.dev/config/keybinds.md)).

Each approval applies to one call. Xum never remembers it. Headless `xum run`, `xum workflow`, ACP clients, and sub-agents refuse such requests at once. A sub-agent cannot ask you anything, but the agent that started it can ask to run the command.

An approved call starts without `BASH_ENV` and without the bash functions that Xum's environment exports (`BASH_FUNC_<name>%%`), as do MCP servers and the commands that Xum runs for itself while the sandbox is on for any project, because a sandboxed command can change the file that `BASH_ENV` names, and bash runs an exported function in place of the program it names, which can run a file in the workspace. An approved call runs `/bin/bash`, which macOS protects, not the first bash on your `PATH`, so a script that needs a newer bash can fail there; an approved background call also starts `/usr/bin/nohup`. The scripts that Xum runs for itself also use `/bin/bash` and the folders that macOS protects (`/usr/bin`, `/bin`, `/usr/sbin` and `/sbin`) in place of your `PATH`, because a folder in your `PATH`, such as an activated `.venv/bin`, can be in the workspace.

> [!WARNING]
>
> An approved command runs with full access to your files, keys, and network. It could read the Xum
> server token, answer later approval cards, or turn the sandbox off. It also runs what it finds in
> the workspace, which sandboxed commands can change: a script, a git hook in the workspace, a file
> that `NODE_OPTIONS` or `PYTHONPATH` names, or a program in a folder of your `PATH` that is in the
> workspace, such as an activated `.venv/bin`, which runs in place of the `git` or `python` that the
> command names. Approve only commands that you read and trust.

## Known limits

* Programs with a sandbox of their own, such as Chrome, Electron, Playwright, Codex, and Claude Code, cannot start it inside the agent sandbox. Start them with their no-sandbox flag. Codex and Claude Code also need their login folders in `extraReadPaths`.
* Commands can read the global git config (`~/.gitconfig` and `~/.config/git`), so that git keeps your name, settings, and aliases. A token in it, for example in `http.extraHeader` or in a remote URL, is readable to commands, and they can use it with an allowed host. Keep git tokens in a credential helper, such as the macOS keychain, which the sandbox closes.
* `git push` over SSH fails, because the `ssh-agent` socket and the SSH keys are closed. `gh` with a stored login fails, because the keychain is closed. Approve the one push outside the sandbox.
* A commit or `git submodule update` that changes the git folder of a submodule fails, because that folder is read-only. Approve the command outside the sandbox. Xum creates worktrees outside the sandbox: `git worktree add` and the submodule checkout after it run with your access, as they do with the sandbox off.
* In a repository whose git folder is outside the workspace (`git init --separate-git-dir`), git cannot write the index, objects or refs, because commands can write `.git` files, so the sandbox does not open the folder that one names. Add that git folder to `extraWritePaths`: its hooks and config stay read-only. A linked worktree needs no entry.
* An instruction file such as `AGENTS.md`, an agent definition or a project skill that links to a file in the workspace's scratch folder (`$XUM_SCRATCH_DIR`) loads as empty, because Xum checks these files without the scratch folder, also outside a turn. Commands and file tools can still read the file.
* File tools check the real path of a file and then open it. A sandboxed command that swaps a symlink between the check and the open can make a file tool read or edit a file that the sandbox hides.
* The VS Code extension shows no approval card yet. A request to run a command outside the sandbox waits there until you stop the agent.
* Project secrets and the bash AI proxy key are still in the environment of agent commands.
* A file in an open folder, such as a toolchain folder or the workspace, is readable to commands, also when a variable names it as the config of a tool. The sandbox hides only the credential files listed in [What commands can read](#what-commands-can-read). Some tools fail when they cannot read the config that a variable names (uv with `UV_CONFIG_FILE`), so the sandbox leaves those files as open as their folder. Keep files with tokens out of the open folders.
* Commands can read the command line and the starting environment of your other programs that are not part of macOS, for example `node` or `python` processes, or Xum when you start `xum server` from a shell. macOS gives the sandbox no way to hide them. A secret in them is readable to commands: a key that your shell profile exports, or the token of `xum server --auth-token` or `XUM_SERVER_AUTH_TOKEN`, with which a command can call Xum's API and turn the sandbox off. With the sandbox on, start `xum server` without a token on its command line or in its environment, so it makes its own.
* The sandbox does not cover terminals that you open, MCP servers (they start outside the sandbox), and the Browser tab.
* A project's own `network` and `allowedHosts` are not a boundary between projects. While a sandboxed command of another project runs, a command can read that command's proxy credential from its process environment and reach the hosts that the other project allows. Settings sets one network mode and host list for all projects, so this matters only when a project in `config.json` has its own `network` or `allowedHosts`.
* In **Allowed hosts only** mode, a background process that `xum run --keep-background-processes` leaves running can reach only loopback after `xum run` exits, because the proxy to the allowed hosts runs in `xum run`.
* With `xum server --no-auth`, a command in the sandbox can call Xum's API on loopback like any other program on your Mac, so it can turn the sandbox off or change any other setting. Do not use `--no-auth` with the sandbox.
* Commands can change the other files in the workspace. When you, your editor, or a Dev Container later runs one of them outside the sandbox, for example a script that `initializeCommand` names or a Dev Container config in another folder, the change runs with your full access. This includes the git hooks and config of a repository nested in the workspace, such as `vendor/tool/.git`: only the `.git` of the workspace itself stays read-only, so the next git command in the nested repository runs what they name. It also includes a hooks folder or program in the workspace that your git config or Xum's environment names, for example with `core.hooksPath`, `core.fsmonitor` or `GIT_SSH_COMMAND`, and a file in the workspace that a link deeper inside a global skill or plugin entry points to, such as `~/.agents/skills/demo/scripts/run.sh`.
* Tool caches, temp folders and the workspace are writable, so a command can change a package that a program outside the sandbox runs later, for example a build in your terminal or editor, also in another project that uses the same cached package (a crate in `~/.cargo/registry`, a Go module, a Maven or Gradle artifact, or a package in the pnpm store), or an MCP server that `npx` or `bunx` finds in the `node_modules` folder of the workspace or gets from a registry that a `.npmrc`, `bunfig.toml` or `uv.toml` in the workspace names. MCP servers and Xum's own git, such as for `git worktree add` and the submodule checkout after it, start with your `PATH`, because they need `npx`, `uvx`, `node` or `git-lfs` from it. A command can change a program in a folder of your `PATH` that it can write, such as an activated `.venv/bin`, and an MCP server whose command names that program, or Xum's own git, runs the change outside the sandbox.
* Xum keeps the output and exit status of each background process in `/private/tmp/mux-bashes`, which commands can write. A command can change what another background process printed, also one of another workspace, or mark one that outlived a restart of Xum as ended, so that Xum archives its workspace while it still runs.
* With Bun 1.4.3 or older, `bunx` fails in the sandbox, because it keeps what it runs in `/private/tmp`, where that stays read-only. Update Bun, or approve the call outside the sandbox.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.