mirror of
https://github.com/docker/docs.git
synced 2026-06-19 07:35:16 +00:00
docs(sandboxes): add workflow patterns page (#25228)
## Summary Adds a new Workflows page to the sandboxes manual covering the patterns that don't fit cleanly in the mechanical usage reference: git strategies (single-agent feature branch and multi-agent parallel branches in clone mode, direct mode), commit signing via SSH agent forwarding, authenticated CLI tools (gh, Docker registry, 1Password via op read), and CI/headless use. Generated by Claude Code --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -79,19 +79,16 @@ sandbox:
|
||||
|
||||
- **Direct mode (default)** — the agent has read-write access to your
|
||||
working tree. Changes the agent makes appear on your host immediately.
|
||||
Best when you're collaborating turn-by-turn with the agent on a single
|
||||
repository.
|
||||
- **[Clone mode](#clone-mode) (`--clone`)** — the agent works on a private
|
||||
Git clone inside the sandbox, with your host repository mounted
|
||||
read-only. The sandbox exposes its clone as a Git remote on your host,
|
||||
so you fetch the agent's commits the same way you'd fetch from any
|
||||
other remote. Best when you want the agent isolated from your host
|
||||
repository — for running multiple agents in parallel, working with
|
||||
untrusted code, or keeping your working tree clean while the agent
|
||||
works.
|
||||
other remote.
|
||||
|
||||
See [Workspace isolation](security/isolation.md#workspace-isolation) for the
|
||||
security model behind each mode.
|
||||
For a comparison of approaches and step-by-step recipes, see
|
||||
[Workflow patterns](workflows.md#git-workflows). For the security model
|
||||
behind each mode, see
|
||||
[Workspace isolation](security/isolation.md#workspace-isolation).
|
||||
|
||||
### Direct mode (default)
|
||||
|
||||
@@ -123,79 +120,17 @@ $ sbx run my-sandbox
|
||||
```
|
||||
|
||||
The clone follows whichever ref your host repository has checked out at
|
||||
create time. No new branch is created automatically. If you want the agent
|
||||
to work on a dedicated branch, instruct it to run `git checkout -b
|
||||
my-feature` inside the sandbox before it starts editing. Alternatively,
|
||||
open a shell with `sbx exec` and create the branch yourself.
|
||||
create time. No new branch is created automatically.
|
||||
|
||||
> [!NOTE]
|
||||
> Clone mode is fixed at create time. To switch an existing sandbox to
|
||||
> clone mode, remove it and recreate it with `sbx create --clone`.
|
||||
|
||||
#### Reviewing and merging the agent's commits
|
||||
|
||||
The CLI wires the in-sandbox clone as a `sandbox-<sandbox-name>` Git remote
|
||||
on your host. Pull the agent's commits the same way you'd fetch any other
|
||||
remote — no `cd` into a separate directory, no extra tooling:
|
||||
|
||||
```console
|
||||
$ git fetch sandbox-my-sandbox
|
||||
$ git log sandbox-my-sandbox/<branch>
|
||||
$ git diff main..sandbox-my-sandbox/<branch>
|
||||
$ git checkout -b my-feature sandbox-my-sandbox/<branch>
|
||||
$ git push -u origin my-feature
|
||||
$ gh pr create
|
||||
```
|
||||
|
||||
If you asked the agent to work on a dedicated branch, `<branch>` is that
|
||||
branch name. Otherwise it's whatever ref your host repository was on at
|
||||
create time.
|
||||
|
||||
Some agents don't commit automatically. If `git log sandbox-<name>/<branch>`
|
||||
shows nothing new, open a shell in the sandbox and commit from there:
|
||||
|
||||
```console
|
||||
$ sbx exec -it my-sandbox bash
|
||||
$ git commit -am "save work"
|
||||
```
|
||||
|
||||
#### Pushing to your fork from inside the sandbox
|
||||
|
||||
When the sandbox starts, the CLI copies the Git remotes from your host
|
||||
repository (`origin`, `upstream`, and so on) into the in-sandbox clone
|
||||
with their existing URLs. The agent can push to your fork on GitHub
|
||||
directly — for example, by prompting:
|
||||
|
||||
> Commit these changes and push them to a new branch on `origin`.
|
||||
|
||||
The push uses the same `git push origin ...` invocation the agent would
|
||||
run on the host. This is interchangeable with fetching the commits to
|
||||
your host first and pushing from there.
|
||||
|
||||
Local-path remotes (`file://` URLs, filesystem paths) aren't copied, since
|
||||
they aren't reachable from inside the sandbox.
|
||||
|
||||
#### Running multiple branches in parallel
|
||||
|
||||
A single sandbox can hold several branches at once. Each branch the
|
||||
agent commits to appears as a separate ref on the `sandbox-<name>`
|
||||
remote, so you can fetch them independently from the host:
|
||||
|
||||
```console
|
||||
$ git fetch sandbox-my-sandbox
|
||||
$ git log sandbox-my-sandbox/feature-a
|
||||
$ git log sandbox-my-sandbox/feature-b
|
||||
```
|
||||
|
||||
A few common ways to have the agent start each task on its own branch:
|
||||
|
||||
- A subagent orchestrator such as Claude Code's
|
||||
[agents view](agents/claude-code.md#agents-view) dispatches each task
|
||||
to a subagent that creates its own worktree inside the clone.
|
||||
- Agent-level instructions in `CLAUDE.md`, an orchestration skill, or a
|
||||
system prompt include a rule to start each task on a new branch.
|
||||
- For one-off tasks, ask the agent to switch to a new branch before it
|
||||
starts.
|
||||
The CLI copies the Git remotes from your host repository (`origin`,
|
||||
`upstream`, and so on) into the in-sandbox clone. The agent can push to
|
||||
your fork directly using the same remote names. Local-path remotes
|
||||
(`file://` URLs, filesystem paths) aren't copied, since they aren't
|
||||
reachable from inside the sandbox.
|
||||
|
||||
#### Sandbox lifecycle and the Git remote
|
||||
|
||||
@@ -230,43 +165,7 @@ rejected at create time in two cases:
|
||||
You can also create a Git worktree yourself and run an agent inside it
|
||||
without `--clone`, but the sandbox won't have access to the `.git`
|
||||
directory in the parent repository, so the agent can't use Git at all.
|
||||
Clone mode is the supported alternative for working on a separate branch.
|
||||
|
||||
### Signed commits
|
||||
|
||||
Sandboxes can sign Git commits with SSH keys from your host agent. The private
|
||||
key stays on your host.
|
||||
|
||||
On the host, load the key into your SSH agent:
|
||||
|
||||
```console
|
||||
$ ssh-add ~/.ssh/id_ed25519
|
||||
```
|
||||
|
||||
Inside the sandbox, check that the forwarded agent exposes the key:
|
||||
|
||||
```console
|
||||
$ ssh-add -L
|
||||
```
|
||||
|
||||
Configure Git globally inside the sandbox to use SSH commit signing. This
|
||||
writes to the sandbox user's Git config, not your repository's `.git/config`.
|
||||
Use an inline public key instead of a key file path, because host paths such as
|
||||
`~/.ssh/id_ed25519.pub` might not exist in the sandbox:
|
||||
|
||||
```console
|
||||
$ git config --global gpg.format ssh
|
||||
$ git config --global user.signingkey "key::$(ssh-add -L | head -n 1)"
|
||||
```
|
||||
|
||||
Then commit as usual:
|
||||
|
||||
```console
|
||||
$ git commit -S
|
||||
```
|
||||
|
||||
For common signing failures, see
|
||||
[Sandbox commits aren't signed](troubleshooting.md#sandbox-commits-arent-signed).
|
||||
See [Host worktree](workflows.md#host-worktree) in Workflow patterns.
|
||||
|
||||
## Reconnecting and naming
|
||||
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
---
|
||||
title: Workflow patterns
|
||||
linkTitle: Workflows
|
||||
weight: 30
|
||||
description: Common workflow patterns for Docker Sandboxes, covering git strategies, authenticated tools, commit signing, and CI integration.
|
||||
keywords: docker sandboxes, sbx, workflows, clone mode, git, branches, commit signing, github cli, ci, headless
|
||||
---
|
||||
|
||||
## Git workflows
|
||||
|
||||
Sandboxes support three approaches for working with Git repositories. The
|
||||
right choice depends on whether you want branch isolation and whether you
|
||||
plan to run tasks in parallel:
|
||||
|
||||
| | Direct mode | Clone mode (`--clone`) | Host worktree |
|
||||
| ------------------------- | ---------------- | ---------------------------- | ----------------------------- |
|
||||
| Branch management | You, on the host | Agent, inside the clone | You, on the host |
|
||||
| Changes visible on host | Immediately | After fetch or agent push | Immediately |
|
||||
| Agent can use Git | Yes | Yes | No |
|
||||
| Parallelism | No | Multiple agents, one sandbox | One sandbox per parallel task |
|
||||
| Mode fixed at create time | No | Yes | — |
|
||||
|
||||
### Direct mode
|
||||
|
||||
The simplest approach. The sandbox mounts your host working tree directly —
|
||||
the agent edits files in place and changes appear immediately. You manage
|
||||
branches yourself.
|
||||
|
||||
1. Check out the branch you want to work on:
|
||||
|
||||
```console
|
||||
$ git checkout -b feat/my-feature
|
||||
```
|
||||
|
||||
2. Start the sandbox. No special flags needed:
|
||||
|
||||
```console
|
||||
$ sbx run claude
|
||||
```
|
||||
|
||||
3. The agent edits files in your working tree. Review diffs, stage, and
|
||||
commit as you normally would:
|
||||
|
||||
```console
|
||||
$ git diff
|
||||
$ git add -p
|
||||
$ git commit
|
||||
$ git push -u origin feat/my-feature
|
||||
```
|
||||
|
||||
Because the sandbox mounts your working tree, switching branches on the host
|
||||
also changes what the agent sees. This makes direct mode well-suited for
|
||||
focused, single-branch work where you're collaborating with the agent
|
||||
turn-by-turn.
|
||||
|
||||
### Clone mode
|
||||
|
||||
In clone mode, the sandbox gets a private Git clone. The agent manages its
|
||||
own branches and commits inside that clone; your host working tree is never
|
||||
touched. When the agent is done, you either fetch its branches to the host or
|
||||
ask the agent to push directly to your fork.
|
||||
|
||||
Clone mode is designed for parallelism: a single clone-mode sandbox can hold
|
||||
many branches at once, and subagent orchestrators (such as Claude Code's
|
||||
[agents view](agents/claude-code.md#agents-view)) can dispatch independent
|
||||
tasks to separate agents, each working on its own branch or worktree inside
|
||||
the clone.
|
||||
|
||||
> [!NOTE]
|
||||
> `--clone` is a create-time flag and cannot be changed on an existing
|
||||
> sandbox. If you need to run additional non-clone sandboxes for the same
|
||||
> repository, you would have to remove the clone-mode sandbox first.
|
||||
> Keep a clone-mode sandbox running across multiple tasks rather than
|
||||
> recreating it per task.
|
||||
|
||||
#### Single task
|
||||
|
||||
1. Start a clone-mode sandbox:
|
||||
|
||||
```console
|
||||
$ sbx run --clone claude
|
||||
```
|
||||
|
||||
2. Ask the agent to create a branch before it starts editing:
|
||||
|
||||
> Create a branch `feat/my-feature` and make the changes.
|
||||
|
||||
3. Fetch the agent's branch when it's done:
|
||||
|
||||
```console
|
||||
$ git fetch sandbox-<name>
|
||||
$ git log sandbox-<name>/feat/my-feature
|
||||
$ git diff main..sandbox-<name>/feat/my-feature
|
||||
```
|
||||
|
||||
4. Pull the branch to the host and push, or ask the agent to push directly:
|
||||
|
||||
```console
|
||||
# Pull to host, then push
|
||||
$ git checkout -b feat/my-feature sandbox-<name>/feat/my-feature
|
||||
$ git push -u origin feat/my-feature
|
||||
$ gh pr create
|
||||
|
||||
# Or ask the agent
|
||||
# "Push feat/my-feature to origin and open a PR."
|
||||
```
|
||||
|
||||
#### Parallel tasks
|
||||
|
||||
1. Start a clone-mode sandbox and open the
|
||||
[agents view](agents/claude-code.md#agents-view):
|
||||
|
||||
```console
|
||||
$ sbx run --clone claude
|
||||
```
|
||||
|
||||
2. Dispatch each independent task to a separate subagent. Claude Code handles
|
||||
branch isolation for subagents automatically in agents view. For other
|
||||
agents (such as Codex), add an instruction to `AGENTS.md` to get the same
|
||||
behavior:
|
||||
|
||||
```markdown
|
||||
Always start each task on a new git branch before making changes.
|
||||
```
|
||||
|
||||
3. Fetch all branches when the agents are done:
|
||||
|
||||
```console
|
||||
$ git fetch sandbox-<name>
|
||||
$ git log sandbox-<name>/feat/task-a
|
||||
$ git log sandbox-<name>/feat/task-b
|
||||
```
|
||||
|
||||
4. Check out the branches you want to keep and open PRs as normal.
|
||||
|
||||
### Host worktree
|
||||
|
||||
You can create a Git worktree on your host and point the sandbox at it. The
|
||||
agent edits files directly in the worktree — but because the sandbox mounts
|
||||
only the worktree directory (not the parent repository), it can't resolve the
|
||||
`.git` pointer file and has no Git access. The agent can read and write files,
|
||||
but can't commit, branch, or check status.
|
||||
|
||||
This is useful when you want branch isolation without the create-time
|
||||
commitment of clone mode, and you're comfortable committing from the host
|
||||
yourself after reviewing the changes.
|
||||
|
||||
1. Create the worktree on the host:
|
||||
|
||||
```console
|
||||
$ git worktree add -b feat/my-feature ../my-feature-work
|
||||
```
|
||||
|
||||
2. Start the sandbox with the worktree as the workspace:
|
||||
|
||||
```console
|
||||
$ sbx run claude ../my-feature-work
|
||||
```
|
||||
|
||||
3. The agent edits files. When it's done, commit and push from the host:
|
||||
|
||||
```console
|
||||
$ cd ../my-feature-work
|
||||
$ git diff
|
||||
$ git add -p && git commit
|
||||
$ git push -u origin feat/my-feature
|
||||
$ gh pr create
|
||||
```
|
||||
|
||||
## Commit signing
|
||||
|
||||
Sandboxes forward your host SSH agent into the sandbox, so the agent can
|
||||
sign commits with your SSH key without the private key ever leaving your
|
||||
host.
|
||||
|
||||
1. On your host, make sure the signing key is loaded in your SSH agent:
|
||||
|
||||
```console
|
||||
$ ssh-add ~/.ssh/id_ed25519
|
||||
$ ssh-add -L # confirm the key appears
|
||||
```
|
||||
|
||||
2. Inside the sandbox, configure Git to sign with SSH. Use the forwarded key
|
||||
directly rather than a file path, since host paths don't exist inside the
|
||||
sandbox:
|
||||
|
||||
```console
|
||||
$ git config --global gpg.format ssh
|
||||
$ git config --global user.signingkey "key::$(ssh-add -L | head -n 1)"
|
||||
```
|
||||
|
||||
3. Sign commits as usual:
|
||||
|
||||
```console
|
||||
$ git commit -S -m "feat: my change"
|
||||
```
|
||||
|
||||
To apply this configuration automatically to every sandbox, use the
|
||||
[`git-ssh-sign`](https://github.com/docker/sbx-kits-contrib/tree/main/git-ssh-sign)
|
||||
community kit, which handles all of the above setup. See [Kits](customize/kits.md)
|
||||
if you want to package it alongside other sandbox customizations.
|
||||
|
||||
For troubleshooting, see
|
||||
[Sandbox commits aren't signed](troubleshooting.md#sandbox-commits-arent-signed).
|
||||
|
||||
## Authenticated CLI tools
|
||||
|
||||
The sandbox proxy handles API credentials for model providers automatically,
|
||||
but agents often also need credentials for tools like `gh`, `docker`, or a
|
||||
secrets manager. The pattern is the same in each case: configure the
|
||||
credential on your host once, and the sandbox either forwards it via the
|
||||
proxy or via SSH agent forwarding.
|
||||
|
||||
> [!NOTE]
|
||||
> The `-g` flag stores a secret globally so all future sandboxes can use it.
|
||||
> Sandboxes that already exist when you run `sbx secret set -g` do not
|
||||
> receive the new value. To update a running sandbox, scope the secret to
|
||||
> it directly: `sbx secret set <sandbox-name> <service>`.
|
||||
|
||||
### GitHub CLI
|
||||
|
||||
Store your GitHub token as a sandbox secret. The proxy injects it into
|
||||
outbound requests, so `gh` works inside the sandbox without any additional
|
||||
configuration:
|
||||
|
||||
```console
|
||||
$ echo "$(gh auth token)" | sbx secret set -g github
|
||||
```
|
||||
|
||||
The agent can then create pull requests, open issues, comment on PRs, and
|
||||
interact with the GitHub API the same way it would from your host:
|
||||
|
||||
```console
|
||||
# Inside the sandbox
|
||||
$ gh pr create --title "feat: my feature" --body "..."
|
||||
$ gh issue list
|
||||
```
|
||||
|
||||
The token is never stored in plaintext inside the sandbox. See
|
||||
[GitHub token](security/credentials.md#github-token) for details.
|
||||
|
||||
### Docker registry
|
||||
|
||||
To let the agent push images it builds to a private registry, store registry
|
||||
credentials on your host. The agent can then run `docker build` and
|
||||
`docker push` without any extra authentication:
|
||||
|
||||
```console
|
||||
$ gh auth token | sbx secret set --registry ghcr.io \
|
||||
--username <github-username> --password-stdin
|
||||
$ echo "$ACR_PASSWORD" | sbx secret set --registry myregistry.azurecr.io \
|
||||
--username myuser --password-stdin
|
||||
```
|
||||
|
||||
Images and containers built inside the sandbox run on the sandbox's private
|
||||
Docker daemon, not your host's. They're deleted when the sandbox is removed.
|
||||
See [Registry credentials](security/credentials.md#registry-credentials) for
|
||||
the full reference.
|
||||
|
||||
### Sourcing credentials from 1Password
|
||||
|
||||
If you store credentials in 1Password, use `op read` to populate `sbx` secrets
|
||||
without pasting values manually:
|
||||
|
||||
```console
|
||||
$ op read "op://Work/GitHub/token" | sbx secret set -g github
|
||||
$ op read "op://Work/Anthropic/credential" | sbx secret set -g anthropic
|
||||
```
|
||||
|
||||
The real value stays on your host; the sandbox sees the proxy-managed
|
||||
placeholder as usual.
|
||||
|
||||
## CI and headless use
|
||||
|
||||
For CI environments and scripts where a browser isn't available, authenticate
|
||||
with a Docker Personal Access Token (PAT):
|
||||
|
||||
```console
|
||||
$ echo "$DOCKER_PAT" | sbx login --username <your-docker-id> --password-stdin
|
||||
```
|
||||
|
||||
Generate a PAT from your
|
||||
[Docker account settings](https://app.docker.com/settings/personal-access-tokens)
|
||||
with at least **Read** scope.
|
||||
|
||||
From there, the rest of the `sbx` workflow is the same as interactive use.
|
||||
Create the sandbox in the background with `sbx create`, run agent tasks with
|
||||
`sbx exec`, and clean up with `sbx rm`:
|
||||
|
||||
```console
|
||||
$ sbx create --name ci-task --clone claude
|
||||
$ sbx run ci-task # attach and give instructions, or use sbx exec for one-off commands
|
||||
$ git fetch sandbox-ci-task
|
||||
$ sbx rm ci-task
|
||||
```
|
||||
|
||||
Agent credentials (API keys, GitHub token) can be pre-configured as global
|
||||
secrets so they're available to any sandbox the CI runner creates:
|
||||
|
||||
```console
|
||||
$ echo "$ANTHROPIC_API_KEY" | sbx secret set -g anthropic
|
||||
$ echo "$GITHUB_TOKEN" | sbx secret set -g github
|
||||
```
|
||||
Reference in New Issue
Block a user