Skip to main content

git.sandbox

git.sandbox runs a callback in a temporary copy of a repository. It preserves the live Git index and reconciles formatter changes only when requested. It works in Git hooks, custom commands, and standalone scripts.

def check(box):
steps.test(
name = "Repository checks",
output = "failures",
fail = {"mode": "wait_all"},
steps = [{"name": "format", "type": "shell", "command": "gofumpt -w ."}],
)

git.sandbox(run = check, scope = "staged", fixes = "unstaged")

Arguments​

ArgumentDefaultBehavior
runRequiredCallable receiving one sandbox descriptor.
scope"staged"staged, pr, or all.
base_ref"origin/main"Explicit PR comparison base. Missing refs fail; Atmos never fetches them.
fixes"none"none reports changes; unstaged merges them into working files without staging.
fail_on_changesTrueFail if tracked sandbox files changed, including when fixes were applied. Use False for a formatting command.
env{}Subprocess environment overrides within the callback.
path_prepend[]Tool directories to prepend to the inherited PATH. Relative paths resolve before entering the sandbox.

For staged, the checkout contains the caller's index, including the temporary index used by git commit --only. For pr, the selected files come from the three-dot diff against base_ref; for all, every indexed file is selected. Both pr and all inspect current tracked working files, including unstaged edits. Untracked working files are not copied.

Sandbox descriptor​

Field or methodPurpose
rootAbsolute source repository path.
pathAbsolute temporary checkout path.
scopeSelected scope.
baseResolved PR base commit, or HEAD for staged/all.
filesSelected repository-relative paths, excluding deletions for staged/pr.
addedAdded paths in the staged index, or PR diff for pr.
track(paths)Include additional formatter outputs, such as go.sum, before modifying them.
copy(paths)Copy existing regular support files, such as a prebuilt linter, preserving modes and timestamps. Destinations must not exist. These copies are never applied back.

fs calls, exec.run, exec.which, atmos calls, and nested steps use the sandbox execution directory. Process settings are scoped to the callback; Atmos does not change its process-wide directory or environment. Loaded script functions still resolve load() relative to their source files. Component handles retain their own component execution context. The env dictionary remains the script's declared inputs; use env= to override subprocess variables.

Fixes and failures​

By default, changes fail the call and leave working files untouched. With fixes = "unstaged", Atmos merges fixes with existing unstaged edits when possible. Overlapping or concurrent changes leave the original file untouched and save a recovery patch with before/after copies. The error names their location.

Checks can fail after making useful fixes: Atmos still reconciles those fixes and preserves the check failure. Callback defer calls run before reconciliation. Cancellation prevents reconciliation and removes the temporary checkout. Cleanup also runs when a check fails. The callback's return value is returned on success.

The sandbox uses private Git metadata and the source repository's object database. It does not register a linked worktree, create branches, stage files, build binaries, or install tools. It supports initial commits and linked worktrees.

Run modifying checks sequentially. Call track before tools create or modify additional files; only selected and explicitly tracked files are reconciled. Nested git.sandbox calls are rejected. This is filesystem isolation for cooperating checks, not a security boundary: scripts and subprocesses can still access absolute paths outside the temporary checkout.