git push inherit exactly the capabilities the mount declares.
Field reference
mounts is an array on the agent (default []). kind: git is the only mount kind.
"git"
required
The mount kind. Only
git exists.string
required
The repository to fetch. A bare
owner/repo resolves to https://github.com/owner/repo.git; a full URL (https://…) or git@… address passes through unchanged. GitHub App auth requires the owner/repo (GitHub) form.string
required
Absolute path inside the sandbox where the checkout lands, for example
/workspace/widgets. Must start with /. When the agent sets no workingDirectory, the first mount’s mountPath becomes the session’s working directory.string
The ref to fetch and check out — a branch name (
main), a fully qualified ref (refs/pull/128/head), or a template (see Ref templates).When ref is omitted, the staging fetch runs with no refspec, so the checkout resolves to whatever FETCH_HEAD happens to point at. Always set ref explicitly; every shipped template and example does.integer
default:"1"
Fetch depth, a positive integer. Mounts are shallow by default — the checkout contains only the fetched ref at the requested depth, with no tags. Agents that need more history fetch it explicitly inside the sandbox.
object
default:"{ kind: \"none\" }"
Authentication for fetching and pushing. Two kinds:
kind: none— unauthenticated. Works for public repositories; the session gets no GitHub credentials for this mount.kind: githubApp— authenticated through the project’s GitHub App connection. This is what unlocks pushes, the git credential helper, and GitHub MCP tools. Fields below.
string
Pins the GitHub App installation to mint tokens from. Rarely needed: when absent, the platform resolves the installation from the spawning event’s payload (GitHub-triggered sessions carry one), and otherwise from the project’s connection that covers the repository.
object
Sets the git identity for commits made in this mount:
{ name: <string>, email: <string containing @> }. Staging writes it as the checkout’s local user.name/user.email.When the session has an attributable human requester, the platform splits the identity — the requester becomes the git author and commitAuthor the committer — and installs a prepare-commit-msg hook that stamps a Co-Authored-By: trailer for the agent, so commit history records both who asked and which agent wrote the change.object
The permission grant for this repository. Each capability is
none, read, or write (merge is none or write only):One cross-field rule is enforced at apply time:
merge: write requires contents: write and pullRequests: write, because GitHub has no standalone merge permission — merging is authorized through those two.Capabilities map onto the GitHub App installation-token permission body when the platform mints tokens for the mount, always including metadata: read so basic repository reads work at every level. merge maps to no token permission of its own; it is purely a proxy-layer gate on which tools the session may call.Checkout behavior
Mounts are staged when the sandbox is created, before any setup commands run and before the agent’s first turn. For each mount the platform initializes the repository atmountPath (or reuses an existing one), points origin at the resolved URL, then runs a shallow fetch of the ref (--depth <depth> --no-tags), checks out FETCH_HEAD, hard-resets, and removes untracked and ignored files.
Staging re-runs on every sandbox creation — including sandboxes restored from a cached environment snapshot — so the checkout always reflects the ref at session start even when the sandbox image is days old.
For githubApp mounts, a first-turn auth preflight verifies the full in-sandbox credential path end to end before the agent runs; if authenticated git transport cannot be established, the session fails with a platform-owned error rather than surfacing GitHub’s misleading “Repository not found” to the model.
Ref templates
ref may interpolate {{ path.to.value }} tokens against the session’s persisted input. Trigger-spawned GitHub sessions store { triggerEventId, payload }, so PR-scoped agents check out the PR head like this:
payload. prefix is correct — trigger message, initialPrompt, and displayTitle render against the payload directly and reject the prefix (see Variables and templating).
A templated ref makes the agent event-dependent: manual starts and agent-to-agent spawns carry no event payload, so a session whose mount ref cannot be resolved from its input is refused at spawn time, with an error explaining that the agent must be started by a matching event trigger. Each token must also resolve to a scalar (string, number, or boolean).
Working directory and multiple mounts
An agent may declare several mounts; each fetches independently to its ownmountPath. The session’s working directory resolves as:
- No
workingDirectorydeclared → the first mount’smountPath. - Relative
workingDirectory→ resolved against the first mount’smountPath; escaping it fails. Declaring a relative working directory with no mounts also fails. - Absolute
workingDirectory→ used as-is.
name (an authoring-only key, stripped from the stored spec) and otherwise by mountPath: an item with a matching key deep-merges into the imported item, new keys append. Mounts are deliberately not removable with the remove: directive (which supports only tools, triggers, and env) — to change a mount an import gave you, override it by key, or drop the import. See Imports and fragments.
Repository authorization
AgithubApp mount only works for repositories covered by one of the project’s active GitHub connections. Authorization is checked at spawn time, before a session is created: if no active connection covers the repository — it was deleted, renamed, or removed from the GitHub App installation — the spawn is refused, and trigger-driven spawns are suppressed until the connection is restored. If GitHub later refuses access definitively at token-mint time, the platform prunes the repository from the stored grant so future spawns fail fast instead of launching doomed sessions. See Connections and identities.
How mounts feed GitHub access
Mounts are the single policy point for everything GitHub in a session. Two consumers derive their credentials from the mount’s capabilities: GitHub MCP tools. AnygithubApp mount provisions the session’s brokered github MCP server; a kind: github entry in the agent’s tools only narrows the tool allowlist on top of that (and is a no-op without a mount). The proxy mints a fresh, capability-scoped installation token per tool call — the token never enters the sandbox. Capability-gated tool families are enforced at two levels: session-level visibility (a tool appears only if some mount grants the capability) and a per-call re-check against the target repository’s own mount:
merge_pull_requestandenable_pull_request_auto_mergerequiremerge: write.actions_secret_listrequiressecrets: reador better;actions_secret_writerequiressecrets: write.
githubApp mount with the agent-bridge credential helper. Every git network operation fetches a short-lived token from the platform’s credential broker, scoped to the git-wire subset of the mount’s capabilities: contents, plus workflows when granted, plus metadata: read — nothing else rides on the git credential. A mount with contents: none gets no git credential at all. Nothing is persisted in the sandbox; git holds the credential only in process memory.
Examples
A read-only reviewer that checks out the PR head and can comment but never push:.auto/agents/pr-review.yaml
main, pushes branches, opens PRs, and attributes its commits:
.auto/agents/staff-engineer.yaml