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

# Inside the Sandbox

> What an agent finds at runtime: the base image, workspace layout, mounted repositories, the /workspace/auto-docs bundle, environment setup, credentials, and the sandbox lifecycle.

Every session runs inside an isolated cloud sandbox built from the agent's [environment](/reference/environments). This page describes that world from the inside — the filesystem an agent wakes up in, how its repositories got there, what credentials it does and does not hold, and what happens around the edges of a run. Read it when you are writing system prompts that reference sandbox paths or tooling, or debugging why a session's environment does not look the way you expected.

## The base image

Sandboxes are built from a Docker image assembled in two layers: a platform bootstrap that is identical for every environment, followed by the `steps:` your environment declares.

The bootstrap starts from the environment's image preset — `image: { kind: preset, name: node24 }` resolves to `node:24-bookworm-slim` — and then:

1. Installs base dependencies: `ca-certificates`, `curl`, `git`, and `gpg`. The `gh` CLI is deliberately absent — agent GitHub API access goes through the brokered [GitHub MCP proxy](/runtime/github-mcp), and git authentication comes from a credential helper.
2. Installs both harnesses at pinned versions: `@anthropic-ai/claude-code` and `@openai/codex`. Every sandbox is capable of running either harness; the agent's `harness:` field selects which one drives the session.
3. Installs auto's agent-bridge runtime at the platform's pinned release. It runs the harness inside the sandbox and provides the git credential helper.
4. Creates the workspace user and directories (see below).
5. Unpacks the documentation bundle into `/workspace/auto-docs`.

Your environment's `steps:` are appended after the bootstrap as literal Dockerfile commands, so a step like `RUN apt-get update && apt-get install -y postgresql-client` bakes tooling into the image. Resource settings (`resources.cpuCount`, `resources.memoryMB`) size the sandbox.

```yaml .auto/fragments/environments/agent-runtime.yaml theme={null}
environment:
  name: agent-runtime
  image:
    kind: preset
    name: node24
  resources:
    memoryMB: 8192
  steps:
    - RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client jq && rm -rf /var/lib/apt/lists/*
    - RUN npm install -g tsx
```

<Note>
  Node.js (with npm) is the only language toolchain in the `node24` preset. If an agent needs anything else — Python packages, Go, a database client — bake it in with `steps:`. A good system-prompt habit is to list the preinstalled CLIs the agent may rely on and tell it to verify anything else with `command -v` first.
</Note>

## Filesystem layout

The agent process runs as the non-root user `user` (group `user`), home `/home/user`. Both `/workspace` and `/home/user` are owned by that user.

| Path                   | Contents                                                                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `/workspace`           | The workspace root. Git mounts conventionally live here (e.g. `/workspace/platform`).                                                      |
| `/workspace/auto-docs` | The bundled auto documentation: `docs/` (platform guides) and `examples/` (complete `.auto/` example directories). Baked into every image. |
| `/home/user`           | The workspace user's home. Harness state lives here (e.g. `/home/user/.claude`), and environment setup caches must live under it.          |
| *your mount paths*     | One directory per `mounts:` entry, at exactly the `mountPath` you declared.                                                                |

### The `/workspace/auto-docs` bundle

Every sandbox carries a self-contained documentation bundle so agents can answer "how does auto work" questions and write `.auto/` configuration without network access to a docs site. It contains a `docs/` directory (index, resource model, agents and triggers, tools and connections, Auto MCP, CI/CD, environments, glossary, design notes) and an `examples/` directory with complete, working `.auto/` example projects (code review, chat assistant, agent fleet, and more). Point agents that manage auto configuration at it — for example, "read `/workspace/auto-docs/docs/resource-model.md` before editing `.auto/`".

## Mounted repositories

Each `kind: git` entry in the agent's `mounts:` becomes a checkout the platform stages before the first agent turn (see the [mounts reference](/reference/mounts) for the declaration syntax). Staging is a reconciliation, not a plain clone:

1. The mount directory is initialized (or reused, on a resumed sandbox) and `origin` is pointed at the repository URL. A bare `owner/repo` resolves to `https://github.com/owner/repo.git`.
2. The requested ref is fetched with `--depth <depth>` (default `1`) and `--no-tags`, then checked out at `FETCH_HEAD` with a hard reset and `git clean -fdx`. The working tree always starts clean at exactly the requested ref.
3. `ref:` values may interpolate `{{payload.…}}` tokens from the triggering event — for example `refs/pull/{{payload.github.pullRequest.number}}/head`. A template that cannot be resolved from the session's input is rejected at spawn time, before a sandbox is ever created.

### Git credentials

For `auth: { kind: githubApp }` mounts, the platform mints a short-lived GitHub App installation token to perform the staging fetch, then configures the checkout to authenticate through the agent-bridge credential helper, scoped per repository URL path. Every subsequent `git fetch`/`git push` the agent runs asks the helper, which relays through auto's web tier to mint a fresh, down-scoped installation token per request. No long-lived GitHub credential is ever written into the sandbox, and the platform verifies the helper path end-to-end before the session's first turn — a session whose git auth cannot be established fails with a platform-owned error instead of a confusing `Repository not found` from GitHub.

### Commit identity and attribution

When a githubApp mount declares `commitAuthor`, the checkout's `user.name`/`user.email` are set to it. If the session's requester (the human the work is attributed to) maps to a verified git identity, the platform sets them as the commit *author* and the agent as the *committer*, and installs a `prepare-commit-msg` hook that stamps attribution trailers (`Co-Authored-By` / `Requested-by`) on every commit. Requester identities asserted by another agent are displayed but never trusted for git author attribution.

## Working directory

The harness starts in the agent's effective working directory:

* With no `workingDirectory:`, it is the **first mount's `mountPath`**.
* An absolute `workingDirectory:` is used as-is.
* A relative `workingDirectory:` resolves against the first mount's path and must stay inside it — an escaping path is rejected.

Environment `setup:` commands run in this same directory. An agent with no mounts and no `workingDirectory` has no working directory, and `setup:` entries are skipped.

## Environment variables and secrets

The agent's `env:` map is resolved at launch. Plain string values pass through; `{ $secret: name }` references resolve from the org/project [secret store](/reference/secrets).

On providers with an egress edge, secrets bound to a specific destination host are **injected at the network edge**: the sandbox environment carries a dead placeholder, and the provider rewrites the matching header on HTTPS requests to exactly that host, so the plaintext never enters the sandbox at all. Where no injection edge exists (local development), secrets inline into the environment. A launch that resolves injected secrets but cannot apply the network rules fails closed rather than starting with placeholder credentials.

Reserved bridge bootstrap variable names cannot be shadowed by agent `env:` — the launch validates this before secret resolution.

Model credentials follow the same principle: harness API traffic goes through auto's model gateway (`ANTHROPIC_BASE_URL` / gateway base URLs plus session-scoped tokens), not through a raw provider API key you manage.

Codex sessions enable the harness's native live web search by default. The agent can use the Responses `web_search` tool without a per-agent MCP tool declaration, for both OpenAI and OpenRouter model selections; ordinary task, credential, and data-handling boundaries still apply.

## Setup: image steps vs. boot commands

Environments have two distinct customization hooks:

* **`steps:`** — Dockerfile commands baked into the image at template build time. Use these for system packages and global tools. They run as root, before any session exists.
* **`setup:`** — named command groups that run **per sandbox boot**, inside the working directory, after mounts are staged and before the agent's first turn. Use these for project installs (`npm ci`, `bundle install`).

Each `setup` entry runs its `commands` under `set -eu` as the workspace user, with a 10-minute timeout per entry. A setup entry can declare a cache:

```yaml theme={null}
setup:
  - name: install
    commands:
      - npm ci
    cache:
      paths:
        - /home/user/.npm
      files:
        - package-lock.json
```

Cache `paths` must be absolute paths under `/home/user`. Before the commands run, the platform restores the cache from a provider volume and validates a cache key derived from the entry's `cache.key` (default: the setup name) plus the SHA-256 of each listed `files` entry — a changed lockfile invalidates the cache. After the commands succeed, the cache directories are persisted back. All cache mechanics run as root around your commands; the cache contents are handed to the workspace user before your commands see them.

## Network

Sandboxes have outbound network access — package installs, `curl`, and any remote MCP server an agent's tools declare with `auth.kind: none` are reached directly. What is *withheld* is credentials, not connectivity:

* Provider tokens (GitHub installation tokens, Slack bot tokens, OAuth access tokens) live only in auto's web tier; the sandbox holds a single session-scoped bearer token for auto's own MCP endpoints, valid for 24 hours.
* Destination-bound secrets are injected at the provider edge (above).
* Attachment and upload flows hand the sandbox short-lived signed URLs rather than provider credentials.

## Lifecycle

A session's runtime moves through a fixed sequence, driven by the platform's dispatch workflow:

<Steps>
  <Step title="Ensure sandbox">
    Dispatch inspects the environment and either creates a fresh sandbox from the environment's (cached) image template, reuses a live one, or resumes a paused one.
  </Step>

  <Step title="Stage mounts">
    Git mounts are authorized against the project, staged with short-lived tokens, and configured with the credential helper, commit identity, and attribution hook.
  </Step>

  <Step title="Run setup">
    Each `setup:` entry runs in the working directory as the workspace user, with cache restore before and cache persist after.
  </Step>

  <Step title="Start the bridge">
    The agent-bridge runtime starts inside the sandbox, connects out to auto's bridge server, receives the harness bootstrap (prompts, MCP server map, model gateway config), verifies git mount auth end-to-end, and runs the harness.
  </Step>

  <Step title="Run, idle, park">
    Message deliveries refresh the sandbox's idle timeout so it never pauses mid-turn. When a session parks (waiting for events with nothing to do), the sandbox is paused best-effort; a later delivery resumes it. A paused sandbox that resumes within the provider's window keeps its workspace — mounts are re-reconciled to the requested ref, but untracked state under `/home/user` survives. A sandbox that expired instead is recreated fresh.
  </Step>
</Steps>

By default the harness runs with approvals bypassed — the sandbox itself is the isolation boundary, so unattended sessions never park on permission prompts. An environment can set `approvals: prompt` to opt back into the harness's own approval escalation; today only the codex harness honors it (claude-code always runs with bypassed permissions).

## Where output goes

Nothing an agent writes to the sandbox filesystem is an output by itself — sandboxes are disposable. Durable output leaves through:

* **Git**: commits pushed through the mounted checkout's credential helper.
* **Tools**: pull requests and comments via [GitHub tools](/runtime/github-mcp), messages via [chat tools](/runtime/chat-tools), platform effects via [auto tools](/runtime/auto-tools).
* **The transcript**: every turn, tool call, and result is persisted to the session record, visible live on the session's web page and queryable afterward with the `auto.sessions.*` introspection tools.
* **Runtime logs**: sandbox-level logs are tailed (redacted) into the session's diagnostics, surfaced by `auto.sessions.summary`.

When an agent finishes, it does not "save" anything — it pushes, posts, or binds, then archives its session (see [sessions](/concepts/sessions)).
