.auto/agents/. This page is the exhaustive reference for that document: every field, its type, whether it is required, its default, and the constraints the schema enforces at apply time. For the conceptual tour of what an agent is, start with Agents; for the full trigger grammar, see Triggers.
File layout and compilation
Agent files live at.auto/agents/*.yaml (.yml and .json are also accepted). A single file may contain multiple YAML documents separated by ---; each document compiles into one agent. There is no kind:/metadata:/spec: envelope — fields sit at the root of the document, and legacy envelopes are rejected with an error pointing at the facade format.
Reusable fragments live under .auto/fragments/ and are pulled in with imports:. Legacy directories are rejected outright: .auto/sessions/, .auto/environments/, and .auto/identities/ all fail apply with an error telling you to move the content into .auto/agents (environments and identities are inline-only now).
Compilation follows a fixed order for each document:
- Merge each entry in
imports:in listed order (later imports win per-field). - Apply
remove:directives against the merged import result. - Merge the document’s own fields last — the document always wins.
name, harness, and environment. Everything else is optional or defaulted. Imports typically supply harness and environment, which is why a thin agent file that consists of a name and an import is common:
.auto/agents/pr-review.yaml
Unknown root-level keys in an agent document are silently ignored — the compiler only routes keys it knows about. A typo’d top-level field name does not fail apply; read the applied spec back with the
auto.resources.get tool when a field seems to have no effect. Strict unknown-key rejection does apply inside structured fields such as model, session, and triggers.Metadata
string
required
The agent’s resource name, unique within the project. Trimmed, 1–128 characters, matching
[A-Za-z0-9_.-]+.The name default is special: an agent named default receives Auto’s built-in Default base before its own imports, so name: default alone is a complete, runnable agent.map of string to string
Free-form labels attached to the agent resource. Keys must be non-empty.
map of string to string
Free-form annotations, same shape as
labels.Authoring controls
These fields steer compilation and are stripped before the spec is validated — they never appear in the applied resource. Full semantics live in Imports and fragments and Variables and templating.string or string[]
Files to merge beneath this document, in order. Also spelled
import; when both are present, imports wins. Two path forms are accepted:- A relative path to another file in the bundle, resolved against the importing file’s directory. Absolute paths and URLs are rejected (“Agent import must be a relative path”).
- A managed-template specifier —
@scope/name@version/subpath(for example@auto/agents@latest/pr-review.yaml). The version defaults to@latestwhen omitted; the file subpath is required. See Managed templates.
map of name to string | number | boolean
Values substituted into
{{ $name }} tokens in imported content only — the declaring document’s own body is never substituted. Names must match [A-Za-z_][A-Za-z0-9_]*; numbers and booleans are coerced to strings. Declared only on the entry document; the scope flows down the whole import tree.Runtime tokens without a $ (such as {{ github.review.htmlUrl }}) never match and pass through untouched. When GitHub Sync applies the file, it supplies context variables (for example repoFullName and githubConnection) beneath your declared map — a declared value always wins.map of target to string or string[]
Deletes named items from the merged import result before this document’s own fields merge on top. Supported targets are exactly
tools, triggers, and env; any other target fails with “Unsupported agent remove target”. Names key into the tool alias, the env var name, and for triggers the item’s name, else its event, else its comma-joined events, else cron:<cron>:<timezone> with the timezone exactly as authored — empty when the trigger declares none (cron:0 8 * * *:), since the UTC default is applied only at validation, after merging. Mounts are deliberately not removable.Merge semantics per field
When multiple imports (or an import and the document body) set the same field, the winner depends on the field family:File-backed strings and append
systemPrompt, initialPrompt, and onReplace accept three value forms:
- A plain string.
file: <relative path>— the content of a file, resolved against the declaring file’s directory. Absolute paths and URLs are rejected; a missing file fails compilation.append: <string>— exactly one key with a string value. Concatenates onto the imported base with your exact whitespace (no hidden separator). Anappendthat never finds a base fails at compile time; a plain value merging over a pending append fails with an error telling you to import the base document before its append overlay.
Harness and model
enum
required
The agent runtime. One of
claude-code or codex. Required after merge (“Agent requires harness”) — typically supplied by an imported fragment or template.object
Model selection. Strict object; when present,
model.id is required. Omitting model entirely uses the harness default: claude-code runs claude-opus-4-8 on anthropic, codex runs gpt-5.6-sol on openai.enum
One of
minimal, low, medium, high, xhigh, max — validated per harness and model. claude-code accepts low through max and defaults to high. codex accepts minimal through xhigh and defaults to medium, with per-model narrowing for OpenRouter models (for example z-ai/glm-5.2 accepts only high and xhigh; x-ai/grok-4.5 accepts medium and high).Prompts and display
string
The agent’s system prompt. Trimmed, 1–100,000 characters. Accepts the
file: and append: forms described above.string
The first message delivered when a trigger spawns a session. Trimmed, 1–20,000 characters. Renders
{{ … }} tokens against the normalized event payload at spawn time — {{ github.pullRequest.number }}, {{ chat.channelId }}, {{ message.text }}. Tokens with a {{ payload.… }} prefix are rejected at apply time with a message telling you to drop the prefix (that prefix is valid only on mount ref templates). Accepts file: and append:.string
Session title shown in listings. Either the literal
infer (the platform infers a title) or a template string, trimmed, 1–20,000 characters, rendered against the event payload with the same no-payload.-prefix rule as initialPrompt.Environment
string or object
required
The sandbox runtime the agent’s sessions run in. Required after merge (“Agent requires environment”). Either the name of an environment generated elsewhere in the bundle, or an inline object — the compiler turns an inline object into a generated environment resource and stores only its name on the agent. Identical inline environments that share a name across files dedupe; different content under the same name fails apply (“Conflicting generated resource”).The inline object carries the environment’s metadata (
name, required; optional labels and annotations) alongside its spec fields. The spec is strict. Full details on presets, setup caching, and build behavior are on Environments..auto/fragments/environments/agent-runtime-base.yaml
Environment variables (env)
map
default:"{}"
Environment variables injected into the agent’s sessions. Keys must match
[A-Za-z_][A-Za-z0-9_]*. Each value is either a plain string or a secret reference:$secret: <name>— resolves a project secret at launch.optional: true— when the secret does not exist, the variable is omitted instead of failing the session launch, and apply-time validation does not require the secret to be set.
remove.env.Identity
string or object
How the agent presents itself on provider surfaces (Slack app, GitHub attribution, Telegram bot). Either the name of an identity resource generated elsewhere in the bundle, or an inline object; an inline identity without an explicit name inherits the agent’s name. The object is strict and requires at least one field. Full realization flow (connecting the identity to providers) is on Identity.
Mounts
object[]
default:"[]"
Repositories checked out into the sandbox. The only mount kind is
git. Mounts are merged across imports by name, else mountPath, and are deliberately not removable via remove. Full capability semantics and the credential flow are on Mounts.Tools
map of alias to tool
default:"{}"
Tools exposed to the agent’s sessions, keyed by alias. An alias is a resource name (1–128 chars,
[A-Za-z0-9_.-]+); the alias workspace is reserved by Claude Code. Every tool variant additionally accepts disabled: true to keep the declaration in place while switching the tool off. Variants are discriminated on kind; the full runtime behavior of each is documented on Tools.Merged as a named map across imports; individual tools are removable via remove.tools.If a referenced connection has no active grant, apply fails — unless the tool declares optional: true, in which case apply silently skips it and re-activates it on the next apply once the connection exists.Triggers
object[]
default:"[]"
Events that wake the agent. Each entry is either an event trigger or a heartbeat trigger (
kind: heartbeat). This section summarizes the shape; the complete grammar — every field, the where filter operators, routing semantics, and cross-field validation rules — is on Triggers, and the event vocabulary is in the event catalog.Shared fields on both shapes:routing(required):kind: spawn(new session per event, optional bind-at-spawn),kind: deliver(deliver into existing sessions, withrouteByandonUnmatched: drop | warn | error | spawn), orkind: bind(resolve the bound session for atarget— one ofgithub.pull_request,github.issue,slack.thread,agent.singleton,linear.issue,auto.session— withonUnmatched, optionalrelease, and optionalobservedTarget).where(optional, default empty = match all): a map of payload path to clause. Paths are a single bare key or$.dot.separated.segments; clauses are a bare scalar for equality or exactly one ofcontains,exists,in,notIn,changedTo.message(optional, 1–20,000 chars): template rendered against the event payload and delivered to the routed session.attachedUserPrompt(optional, 1–20,000 chars, non-whitespace): extra user prompt; spawn-routing triggers only.checks(optional): GitHub check runs the session must complete; legal only ongithub.pull_request.*events. Each check hasname,displayName,description, optionalinstructions, and optionaltimeout/beginTimeout/completeTimeoutobjects (seconds1–604,800,conclusion: success | failure | skipped;timeoutandbeginTimeoutare mutually exclusive).fallback(optional, defaultfalse): fires only when no non-fallback trigger on the same endpoint and event key matched.name(optional): authoring-only merge key, stripped at compile time.
eventorevents(exactly one required): the event key or a list of unique keys; a list expands into one stored trigger per event.connection(optional): the connection the trigger is bound to.optional(optional boolean): apply silently skips the trigger when the referenced connection has no active grant; it re-activates on the next apply.endpointandauth(optional): custom-webhook ingress key and its verification (kind: hmac_sha256 | bearer_tokenwithsecretRef, orkind: none).
kind: heartbeat) replace the event fields with:cron(required): a cron expression, 1–512 chars.timezone(optional, defaultUTC): 1–128 chars.
event, connection, optional, endpoint, and auth are forbidden on heartbeat triggers.Session policy
object
default:"{}"
Per-session lifecycle policy. Strict object.
Spend caps
object
USD spending limits for the agent. Strict object; all fields optional. Each value is a nonnegative decimal string (not a number) with at most 10 integer and 10 fractional digits, matching the platform ledger’s precision; trailing zeros are canonicalized away. Enforcement behavior is described in Runtime controls.Daily and monthly windows reset at UTC calendar boundaries.
Concurrency and replacement
integer
Cap on live sessions for the agent. Only
1 is accepted — a concurrency-1 agent keeps at most one live session (the agent slot); larger pools are a deliberate non-goal. Declaring any other value fails apply with a message saying so.string
The literal
auto, or absent. replace: auto asserts the agent’s state is externally reconstructable, so the platform may stop a stale or failed slot session and spawn a replacement on the latest spec. Requires concurrency to be set (“replace requires concurrency”).string
The rebuild-on-wake prompt delivered to a platform-spawned replacement session. Trimmed, 1–20,000 characters; accepts
file: and append: forms. Requires replace: auto — nothing else consumes it.string[]
Agent-type names whose sessions this agent may manage (stop) within its project, max 64 entries. Authority is granted by agent type, not spawn provenance — a replacement session of a managing agent controls sessions its predecessor spawned. Self-control is always implicit, and unknown names are inert rather than invalid.
Bindings
map of target to policy
default:"{}"
Per-target-type binding policy, keyed by binding target type (
github.pull_request, github.issue, slack.thread, linear.issue, auto.session). agent.singleton is rejected as a key — the pool slot has its own release lifecycle. Each entry is strict.Working directory
string
The directory sessions start in inside the sandbox. Trimmed, non-empty. Typically points at a mount path, for example
/workspace/auto.Minimal agent
After all imports merge, a compilable agent needs exactly three things:name, harness, and environment. Everything else defaults — env: {}, mounts: [], triggers: [], session: {}, bindings: {}, tools: {}. An agent with no triggers is valid; it can only be started manually or by another agent.
The shortest valid agent file is one line, because Auto’s built-in Default base supplies harness and environment for the reserved name:
.auto/agents/default.yaml