name and harness. This page is the exhaustive reference for the environment spec; for how environments fit the bigger picture, see Environments.
Declaring an environment
Environments are declared inline on the agent — there is no standalone environment file. A.auto/environments/ directory is rejected at apply time with an error telling you to define environments inline in .auto/agents YAML, using fragment imports under .auto/fragments/environments/ for reused runtimes.
The agent’s environment field takes one of two forms:
- An inline object. The compiler splits it into metadata (
name,labels,annotations) and spec (everything else), and emits a generated environment resource. The agent’s stored spec keeps only the environment’s name. - A string name referencing an environment generated elsewhere in the same bundle. A string overrides an inline object during import merge, and vice versa.
.auto/fragments/environments/agent-runtime.yaml
.auto/agents/staff-engineer.yaml
- Deduplication. When several files generate an inline environment with the same name, the compiled specs must be identical (compared structurally, so key order does not matter). Identical copies dedupe into one resource; divergent content under the same name fails apply with a “Conflicting generated resource” error.
- Merge semantics. Across imports, inline
environmentobjects deep-merge key-wise, but arrays replace rather than concatenate — a later import’sstepsorsetuparray overwrites the earlier one entirely. A fragment that needs “the base steps plus more” must restate the base steps.
Field reference
The environment spec is strict: unknown keys fail validation.string
required
Resource name for the generated environment. Trimmed, 1–128 characters, matching
[A-Za-z0-9_.-]+. Required when declaring inline.map of string to string
Free-form labels on the generated environment resource.
annotations is accepted with the same shape.object
required
The base image. Choose exactly one strict shape:
{ kind: "preset", name: <preset> }resolves a name from the platform’s runtime-preset registry.{ kind: "base", ref: <image> }uses one Docker/OCI image reference directly. The trimmed reference is 1–512 characters and cannot contain whitespace,#, or\, or start with-.
An unknown preset name fails with
Unknown runtime preset. Direct refs may include a registry, tag, or digest. Mutable tags can resolve to different bytes on later builds; auto preserves the authored reference and does not currently resolve and persist a digest, so pin a digest when reproducibility matters.On top of either arm, auto bakes its own bootstrap layers into every image before your steps run: base packages (ca-certificates, curl, git, gpg), platform-pinned versions of Claude Code and Codex plus auto’s agent-bridge runtime, a non-root workspace user named user (home /home/user, workspace /workspace), and an offline copy of the auto docs at /workspace/auto-docs. gh is deliberately absent — agent GitHub API access goes through the brokered GitHub MCP surface and git auth comes from the credential helper (see Mounts).Direct bases additionally run the debian-contract-v0 probe as root before that bootstrap. They must be Linux/amd64, expose /bin/sh, use glibc 2.28 or newer, and provide git or the current Debian/Ubuntu package path that installs it. auto synthesizes this single-stage build; it does not import a repository Dockerfile. Follow Validate an environment image for the exact local Docker preflight and classified incompatible fixture.array of string
default:"[]"
Dockerfile instructions appended to the generated image build, after auto’s bootstrap layers. Each entry is a raw Dockerfile line — in practice Steps are baked into the image, so they run at image build time — not per session — and their results are shared by every session using the environment. Pin versions (and verify checksums for downloaded binaries) to keep image builds reproducible.
RUN … commands installing system packages and global CLIs:array of object
default:"[]"
Named command groups that run per session, inside the sandbox, after git mounts are staged. Each entry:
Setup commands run in the session’s working directory (the first mount’s
mountPath unless the agent sets workingDirectory), as the non-root user account, through /bin/sh -lc with set -eu prepended — the first failing command fails the step. Each setup entry has a 10-minute timeout.Sessions with no working directory — no mounts and no absolute workingDirectory — skip setup entirely.Use setup for workspace-dependent work such as dependency installs; use steps for slow-changing system tooling:object
Declares the cacheable state behind a setup entry: the directories that hold its expensive artifacts and the workspace files that define their identity.
Setup runs in full when the platform builds the environment’s sandbox snapshot, and the snapshot persists everything the commands produced — including the directories under
paths. Sessions reusing the snapshot re-run the setup commands against that warm state. The cache object is part of the snapshot cache key alongside the commands themselves (see setupCache), so bumping key is the deliberate lever to force a fresh snapshot build when an artifact must be rebuilt even though the commands did not change.In the example above, npm ci --prefer-offline reads the npm cache at /home/user/.npm that the snapshot build already filled, skipping the network fetch that dominates install time.object
Controls how long the sandbox provider may reuse a cached sandbox snapshot that already ran this environment’s setup. Shape:
{ ttl: <duration> }, where ttl matches [1-9][0-9]*(s|m|h|d) — for example 30m, 24h, 7d. When absent, the default reuse window is 7 days.The snapshot cache is keyed by the image build, the mounts, the setup commands, and the working directory, so changing any of those produces a fresh build regardless of TTL. Mounts are re-fetched per session even on a snapshot hit — the TTL only bounds staleness of the baked setup results, never of your code.object
Sandbox sizing. At least one field is required when the object is present:
map
default:"{}"
Environment variables declared on the environment resource. Keys match
[A-Za-z_][A-Za-z0-9_]*. Each value is either a literal string or a secret reference:$secret names a platform secret; apply-time validation checks that required secret references exist. optional: true marks a reference the runtime may resolve to nothing — a missing secret omits the variable instead of failing, and apply does not require the secret to be set. Agents declare env vars with the same value forms at the agent level (see the agent file reference and Secrets)."bypass" | "prompt"
Harness approval posture for sessions running in this environment. Absent means
bypass: every harness action is auto-approved, because the sandbox is the isolation boundary and unattended sessions must never park on approval questions. prompt opts back into the harness’s own approval escalation for operator-attended use.Only the codex harness consults this setting today; claude-code always bypasses, so prompt under a claude-code agent is currently a no-op.Complete example
A tooled coding runtime, shared by several agents through a fragment import:.auto/fragments/environments/agent-runtime.yaml
env: at the fragment’s root is the agent-level env field (this fragment is an agent document that agents import), while environment.env would attach the variables to the environment resource itself. Both accept the same value forms.
Changing
steps changes the image and forces a rebuild on the next session; changing setup or the mounts invalidates the sandbox snapshot cache. Neither requires any manual action — the next session picks up the new environment automatically after the change is applied through GitHub Sync.