# Sandbox environment reference (/reference/sandbox-environment)



This page describes the environment your `setup.sh`, `start.sh`, and the agent run in: the preinstalled tools, the workspace layout, the environment variables the runtime sets, and what is deliberately kept out of the sandbox.

## Preinstalled software [#preinstalled-software]

Every provider's image installs the same tools. The per-provider image targets differ only in their base: the Vercel target is built on Amazon Linux, and the Vercel and OpenComputer targets use Node.js 24.

| Area               | What is installed                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| Operating system   | Debian with `build-essential`, `git`, `curl`, `jq`, `unzip`, `openssh-client`, `ffmpeg`, and `ca-certificates`      |
| Source control     | GitHub CLI (`gh`)                                                                                                   |
| Node.js            | Node.js 22 (Node.js 24 on the Vercel and OpenComputer targets) with `npm` and `npx`, plus `pnpm`, `bun`, and `bunx` |
| Python             | Python 3.12 with `uv` and `uvx`. `python` and `python3` point at the same interpreter                               |
| Browser automation | The `agent-browser` CLI with a headless Chrome for Testing build at `/usr/local/bin/google-chrome`                  |
| Agent harnesses    | OpenCode, and the Claude Agent SDK whose wheel bundles the `claude` binary                                          |
| Sandbox tools      | `code-server` (browser VS Code), `ttyd` (web terminal), and Xvfb, Fluxbox, x11vnc, and noVNC for the VNC desktop    |

Version pins live in `packages/sandbox-images/toolchain.json`. Updating the shared toolchain does not refresh existing prebuilt images; rebuild them from Settings › Images or Settings › Environments when they must pick up new tools.

## Workspace layout [#workspace-layout]

| Path                                           | Contents                                                                                                                                                                                                                                     |
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/workspace`                                   | The working directory. A single-repository session is cloned here.                                                                                                                                                                           |
| `/workspace/<repo-name>`                       | In multi-repository sessions each repository is cloned into its own directory named after the repository. The first repository is the primary.                                                                                               |
| `/workspace/.tunnels.env`                      | Written before `start.sh` when the session has `tunnelPorts` configured. Plain `KEY=value` lines usable with `node --env-file`, `bun --env-file`, or `docker compose --env-file`. Not written when no tunnel ports are set or in build mode. |
| `.opencode/skills` under the working directory | Where OpenCode discovers skills. The runtime copies its bundled skills here before launch; managed skills are installed into the workspace before the agent starts.                                                                          |
| `~/.openinspect/claude`                        | The Claude Agent harness's `CLAUDE_CONFIG_DIR`. Managed and bundled skills are staged under `~/.openinspect/claude/skills`. It sits outside every repository so a snapshot never captures a credential with it.                              |

Repository `.opencode/` and `.claude/` directories are read by their respective harness, the same trust boundary as `.openinspect/setup.sh`.

## Environment variables [#environment-variables]

| Variable                                                                   | Set when                                                      | Meaning                                                                                                                                                                                                                                                        |
| -------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `OPENINSPECT_BOOT_MODE`                                                    | Always, for `setup.sh` and `start.sh`                         | One of `fresh`, `repo_image`, `snapshot_restore`, or `build`. Use it to skip work that a prebuilt image or snapshot already did.                                                                                                                               |
| `TUNNEL_SANDBOX_ID`                                                        | In `/workspace/.tunnels.env` when tunnel ports are configured | The sandbox the URLs were resolved for. The runtime uses it to tell a fresh file from one inherited from a snapshot.                                                                                                                                           |
| `TUNNEL_<port>`                                                            | In `/workspace/.tunnels.env`, one line per configured port    | The public URL for that port, for example `TUNNEL_3000=https://…`.                                                                                                                                                                                             |
| `SANDBOX_ID`                                                               | Always                                                        | Identifies this sandbox to the control plane.                                                                                                                                                                                                                  |
| `CONTROL_PLANE_URL`                                                        | Always                                                        | Where the runtime, credential helper, and helper commands call back to.                                                                                                                                                                                        |
| `SANDBOX_AUTH_TOKEN`                                                       | Always                                                        | The sandbox's own short-scoped token for control-plane calls. It authorises one session only.                                                                                                                                                                  |
| `SESSION_CONFIG`                                                           | Always                                                        | JSON describing the session: its id, repositories, MCP servers, and related settings. The runtime and helper commands read the session id from it.                                                                                                             |
| `REPO_OWNER`, `REPO_NAME`                                                  | Repository sessions                                           | The primary repository.                                                                                                                                                                                                                                        |
| `GITHUB_APP_TOKEN`                                                         | Modal snapshot restores only                                  | A clone token so snapshots taken before the credential helper can still boot; fresh and prebuilt-image sandboxes, and every other provider, use the credential helper instead.                                                                                 |
| `RESTORED_FROM_SNAPSHOT`                                                   | Snapshot restores                                             | Marks a restored sandbox.                                                                                                                                                                                                                                      |
| `OPENCODE_CONFIG_CONTENT`                                                  | OpenCode sessions                                             | The generated OpenCode configuration.                                                                                                                                                                                                                          |
| `PYTHONUNBUFFERED`, `PATH`, `HOME`, `USER`, `SHELL`, `TERM`, `PWD`, `LANG` | Always                                                        | Standard process environment.                                                                                                                                                                                                                                  |
| `OPENAI_OAUTH_MANAGED=1`                                                   | OpenAI account mode                                           | The session is bound to a connected OpenAI provider account. `OPENAI_API_KEY` is suppressed and the runtime fetches short-lived access tokens from the control plane.                                                                                          |
| `XAI_OAUTH_MANAGED=1`                                                      | xAI account mode                                              | Same for a connected SuperGrok account; `XAI_API_KEY` and legacy xAI OAuth fields are removed.                                                                                                                                                                 |
| `ANTHROPIC_OAUTH_MANAGED=1`                                                | Claude Agent sessions bound to a connected Claude account     | No Anthropic key is in the user secrets. The harness fetches the credential on every bridge start and passes it to the `claude` process only, as `CLAUDE_CODE_OAUTH_TOKEN`. In key mode the `claude` process receives `ANTHROPIC_API_KEY` instead, never both. |
| `CLAUDE_CONFIG_DIR`                                                        | Claude Agent sessions                                         | Points the `claude` binary at `~/.openinspect/claude`. A user-supplied value that points inside a repository is replaced with the default.                                                                                                                     |
| Your secrets                                                               | Always                                                        | Global secrets plus the session target's secrets, injected at spawn. System variables above take precedence over a secret with the same key, and the reserved names cannot be saved as secrets.                                                                |

The reserved names are listed in full in [Secrets](/configure/secrets).

## What is deliberately absent [#what-is-deliberately-absent]

* Provider API keys in account mode. When a session is bound to a connected OpenAI, xAI, or Anthropic account, the matching key is removed from the environment and only the `*_OAUTH_MANAGED` marker remains.
* Refresh tokens. The sandbox only ever receives short-lived access tokens; refresh tokens stay in the encrypted credential store.
* The commit signing private key. Sandboxes receive only the public key; each commit is signed by the control plane. The key is never delivered to a sandbox file, environment, process, or snapshot.
* A long-lived git token in fresh and prebuilt-image sandboxes. Git credentials are minted on demand (next section).
* The Claude account token outside the `claude` process. OpenCode, code-server, the terminal, and user shells never see it. Code the agent runs from Bash and hooks registered in the repository's `.claude/` settings do inherit it.

## Git credentials [#git-credentials]

`git` is configured system-wide with the credential helper `oi-git-credentials`. Every fetch, push, `ls-remote`, or submodule update asks the control plane for a fresh short-lived SCM credential instead of using a token captured at spawn. A successful response is cached in `/run/oi/scm-creds.json` until shortly before it expires, and concurrent git commands share one request. A refused refresh fails the git command rather than falling back to a stale token. The helper authorises the configured SCM host, so `setup.sh` can clone other private repositories the shared App installation can reach.

## Helper commands [#helper-commands]

| Command               | What it does                                                                                                                                                                                                     |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `oi-git-credentials`  | The git credential helper described above. You do not call it directly; `git` does.                                                                                                                              |
| `oi-git-sign`         | Signs a commit by sending the unsigned commit buffer to the control plane, which returns an SSH signature. Active only when commit signing is configured under Settings › Integrations › GitHub.                 |
| `upload-media <file>` | Uploads a screenshot (PNG, JPEG, WebP) or MP4 recording to the session as a media artifact. MP4 files need `--artifact-type video`; `--caption` adds a caption. The file appears in the session's Media section. |

## Next steps [#next-steps]

* [Lifecycle scripts](/configure/lifecycle-scripts)
* [Sandbox tools](/sessions/sandbox-tools)
* [Secrets](/configure/secrets)
