sha256:62d44d56f1f337d7b05887c2cd194d78c6cc948ecaf5e2c8f072f5f5ce304578
Last pushed
1 day by cdupuis
Type
Sandbox Kit
Manifest digest
sha256:62d44d56f1f337d7b05887c2cd194d78c6cc948ecaf5e2c8f072f5f5ce304578
schemaVersion: "3"
displayName: Claude over ACP
author: Docker, Inc.
description: 'A sandbox an ACP client can drive: a shell base, Claude Code, and the Agent Client Protocol adapter that fronts it — published as one kit. The same three kits compose by hand; this exists so an editor can be pointed at one reference instead of three that have to agree.'
sourceUrl: https://github.com/docker/sandbox-kit-spec
version: 1.0.4
licenses:
- Apache-2.0
kind: workload
provides:
- [email protected]
- [email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/ca-certificates-java@20240118
- deb/ca-certificates@20250419
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/iputils-ping@20240905
- deb/[email protected]
- deb/[email protected]
- deb/less@668
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
- deb/[email protected]
capabilities:
- group:
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[0]
type: com.docker.sandbox/network-policy@1
config:
runtime:
allow:
- api.anthropic.com:443
- platform.claude.com:443
- downloads.claude.ai:443
- claude.com:443
- mcp-proxy.anthropic.com:443
- bridge.claudeusercontent.com:443
declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[0]
- group:
description: Anthropic API access (API key or claude.ai OAuth)
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[1]
type: com.docker.sandbox/credential@1
config:
apiKey:
inject:
- domain: api.anthropic.com
format: '%s'
header: x-api-key
- domain: mcp-proxy.anthropic.com
format: '%s'
header: x-api-key
name: ANTHROPIC_API_KEY
oauth:
credentialFile:
path: ~/.claude/.credentials.json
structure:
claudeAiOauth:
accessToken: '{{.AccessToken}}'
expiresAt: '{{.ExpiresAt}}'
refreshToken: '{{.RefreshToken}}'
scopes: '{{.Scopes}}'
primaryApiKey: '{{.PrimaryApiKey}}'
sentinels:
accessToken: sk-ant-oat01-proxy-managed
refreshToken: sk-ant-ort01-proxy-managed
tokenEndpoint:
host: platform.claude.com
path: /v1/oauth/token
phase: runtime
service: anthropic
description: Anthropic API access (API key or claude.ai OAuth)
declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[1]
- declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[2]
type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/projects
size: 2g
description: Conversation history; grows without bound, gets the headroom
- declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[3]
type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/sessions
size: 512m
description: Per-session state; load-bearing for `claude -c`
- declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[4]
type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/todos
size: 512m
description: TodoWrite state
- declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[5]
type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/shell-snapshots
size: 512m
description: Bash state snapshots across sessions
- declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[6]
type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/statsig
size: 512m
description: Local feature-flag cache
- group:
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[7]
type: com.docker.sandbox/lifecycle@1
config:
install:
- command: |
set -e
ws="${WORKSPACE_DIR:-/}"
esc=$(printf '%s' "$ws" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g; s/\r/\\r/g')
projects="\"/\": { \"hasTrustDialogAccepted\": true }"
[ "$ws" = "/" ] || projects="$projects, \"$esc\": { \"hasTrustDialogAccepted\": true }"
printf '%s\n' "{
\"bypassPermissionsModeAccepted\": true,
\"hasCompletedOnboarding\": true,
\"projects\": { $projects }
}" > /home/agent/.claude.json
chown agent:agent /home/agent/.claude.json
description: Seed Claude bypass and trust flags
env:
- WORKSPACE_DIR
user: "0"
- command: mkdir -p /home/agent/.claude && chown agent:agent /home/agent/.claude
description: Ensure ~/.claude is agent-owned before settings seed
user: "0"
- command: |
set -e
HELPER=''
if [ "${SBX_CRED_ANTHROPIC_MODE:-none}" != none ]; then
HELPER=' "apiKeyHelper": "echo proxy-managed",
'
fi
# Model selection from the create-phase args. The args'
# patterns admit no quote or backslash, so the expanded
# value is safe inside the JSON string. effortLevel accepts
# low/medium/high/xhigh; max and auto persist only through
# CLAUDE_CODE_EFFORT_LEVEL (settings.json rejects them).
model=''
effort=''
MODEL=''
EFFORT=''
ENV_BLOCK=''
[ -z "$model" ] || MODEL=" \"model\": \"$model\",
"
case "$effort" in
'') ;;
max|auto)
ENV_BLOCK=" \"env\": { \"CLAUDE_CODE_EFFORT_LEVEL\": \"$effort\" },
"
;;
*)
EFFORT=" \"effortLevel\": \"$effort\",
"
;;
esac
# Lifecycle hooks for Narwhal (see /usr/local/bin/sbx-claude-hook):
# Stop and StopFailure report a finished turn, Notification the
# moments Claude waits on the user, UserPromptSubmit the prompt
# that names the conversation (Claude Code lists sessions by id
# only). The script never fails, never writes stdout and runs
# async, so a session without the desktop app sees no delay and
# no hook error.
HOOK='{ "type": "command", "command": "/usr/local/bin/sbx-claude-hook claude", "timeout": 10, "async": true }'
HOOKS=" \"hooks\": {
\"Stop\": [ { \"hooks\": [ $HOOK ] } ],
\"StopFailure\": [ { \"hooks\": [ $HOOK ] } ],
\"UserPromptSubmit\": [ { \"hooks\": [ $HOOK ] } ],
\"Notification\": [ { \"matcher\": \"permission_prompt|idle_prompt|elicitation_dialog|elicitation_url_dialog|agent_needs_input\", \"hooks\": [ $HOOK ] } ]
},
"
# The statusLine command is the only place Claude Code exposes
# the live session (model, context window, cost, lines changed);
# sbx-agent-hook forwards it to Narwhal's status bar and prints
# nothing, so no status line is drawn in the terminal. A mixin that
# sets its own statusLine (e.g. claude-sbx-statusline) replaces
# this one and the app's session view goes quiet for that sandbox.
STATUSLINE=" \"statusLine\": { \"type\": \"command\", \"command\": \"/usr/local/bin/sbx-claude-hook claude-status\" },
"
printf '%s' "{
\"themeId\": 1,
\"alwaysThinkingEnabled\": true,
${HELPER}${MODEL}${EFFORT}${ENV_BLOCK}${HOOKS}${STATUSLINE} \"permissions\": { \"defaultMode\": \"bypassPermissions\" },
\"bypassPermissionsModeAccepted\": true,
\"skipDangerousModePermissionPrompt\": true
}
" > /home/agent/.claude/settings.json
description: Seed Claude settings.json from the surfaced auth mode
env:
- SBX_CRED_ANTHROPIC_MODE
user: agent
- command: |
set -e
[ -n "$MCP_GATEWAY_URL" ] || exit 0
claude mcp add mcp-gateway "$MCP_GATEWAY_URL" \
--transport http \
--scope user \
--header "Authorization: Bearer $MCP_SENTINEL_TOKEN_NAME" || true
description: Register the sandbox MCP gateway at install
env:
- MCP_GATEWAY_URL
- MCP_SENTINEL_TOKEN_NAME
user: agent
startup:
- command:
- sh
- -c
- chown -R agent:agent /home/agent/.claude/projects /home/agent/.claude/sessions /home/agent/.claude/todos /home/agent/.claude/shell-snapshots /home/agent/.claude/statsig 2>/dev/null || true
description: Re-own claude session-state volume mount roots to agent
user: "0"
- command: |
set -e
[ -n "$MCP_GATEWAY_URL" ] || exit 0
claude mcp add mcp-gateway "$MCP_GATEWAY_URL" \
--transport http \
--scope user \
--header "Authorization: Bearer $MCP_SENTINEL_TOKEN_NAME" || true
description: Register the sandbox MCP gateway (startup fallback)
env:
- MCP_GATEWAY_URL
- MCP_SENTINEL_TOKEN_NAME
user: agent
declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[7]
- group:
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[8]
type: com.docker.sandbox/agent-skills@1
config:
path: /home/agent/.claude/skills
declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[8]
- group:
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[9]
type: com.docker.sandbox/agent-context@1
config:
contentFile: /usr/share/sandbox/kit/claude-acp-set/context.md.parts/0.md
directory: /home/agent/.claude
filename: CLAUDE.md
declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[9]
- group:
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[10]
type: com.docker.sandbox/agent-context@2
config:
content: |
Claude Code is installed at `/usr/local/bin/claude`. Run `claude` for an
interactive session or `claude -p "<prompt>"` for a one-shot answer.
Authentication is proxy-mediated: `ANTHROPIC_API_KEY` in this container is
a sentinel — the sandbox proxy substitutes the real key bound on the host
(`sbx secret set anthropic`) on requests to Anthropic's APIs. Without a
bound key, `claude` will ask you to log in.
directory: /home/agent/.claude
filename: CLAUDE.md
declarationBlocks:
- "0:0"
source:
kit: docker.io/docker/sbx-kit-claude-mixin:2.1.311
path: capabilities[10]
- group:
description: Drive claude sessions over the Agent Client Protocol
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-acp:0.97.0
path: capabilities[0]
type: com.docker.sandbox/acp@1
config:
agent: claude
command:
- claude-agent-acp
description: Drive claude sessions over the Agent Client Protocol
declarationBlocks:
- "1:0"
source:
kit: docker.io/docker/sbx-kit-claude-acp:0.97.0
path: capabilities[0]
- group:
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-acp:0.97.0
path: capabilities[1]
type: com.docker.sandbox/agent-context@1
config:
contentFile: /usr/share/sandbox/kit/claude-acp-set/context.md.parts/1.md
declarationBlocks:
- "1:0"
source:
kit: docker.io/docker/sbx-kit-claude-acp:0.97.0
path: capabilities[1]
- group:
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-claude-acp:0.97.0
path: capabilities[2]
type: com.docker.sandbox/agent-context@2
config:
content: |
## Claude Code ACP adapter
`claude-agent-acp` is installed at `/usr/local/bin/claude-agent-acp`. It
is an Agent Client Protocol (ACP) server on stdio: a client spawns it and
drives a Claude Code session through the protocol. It is not an
interactive command — with no client on the other end of stdio it sits
silent, so do not run it from this shell to "check" it.
Host tools must attach it to a non-TTY stdin/stdout stream, for example
`sbx exec -i <sandbox> claude-agent-acp`. In Zed, configure an agent
server whose command runs that.
The adapter drives the same `claude` binary this sandbox already has
(the one `command -v claude` finds, unless `CLAUDE_CODE_EXECUTABLE`
names another), so authentication is
the surface `claude` uses: the proxy-mediated Anthropic credential in
`~/.claude/.credentials.json` and `~/.claude/settings.json`. If `claude`
works here, the adapter works with no extra setup and nothing separate to
log in to. Sessions created through ACP share the session-state volumes
with interactive `claude` runs.
declarationBlocks:
- "1:0"
source:
kit: docker.io/docker/sbx-kit-claude-acp:0.97.0
path: capabilities[2]
- group:
capabilities:
- source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[0]
type: com.docker.sandbox/sbx@1
declarationBlocks:
- "2:0"
source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[0]
- group:
capabilities:
- source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[1]
type: com.docker.sandbox/network-policy@1
config:
runtime:
allow:
- deb.debian.org
- dhi.io
declarationBlocks:
- "2:0"
source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[1]
- group:
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[2]
type: com.docker.sandbox/agent-context@1
config:
contentFile: /usr/share/sandbox/kit/claude-acp-set/context.md.parts/2.md
filename: AGENTS.md
declarationBlocks:
- "2:0"
source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[2]
- group:
optional: true
capabilities:
- source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[3]
type: com.docker.sandbox/agent-context@2
config:
content: |
This is a plain shell sandbox on the shell-docker template: bash,
git, apt, Docker (compose/buildx), curl, gh, jq, make, gcc,
Python 3, and Node/npm. Install more with apt; composed kits list
their own capabilities below.
filename: AGENTS.md
declarationBlocks:
- "2:0"
source:
kit: docker.io/docker/sbx-kit-shell:1.0.0
path: capabilities[3]
- group:
optional: true
capabilities:
- source:
kit: the set descriptor
path: capabilities[0]
type: com.docker.sandbox/agent-context@1
config:
contentFile: /usr/share/sandbox/kit/claude-acp-set/context.md.parts/3.md
directory: /home/agent/.claude
filename: CLAUDE.md
declarationBlocks:
- "3:0"
source:
kit: the set descriptor
path: capabilities[0]
- group:
optional: true
capabilities:
- source:
kit: the set descriptor
path: capabilities[1]
type: com.docker.sandbox/agent-context@2
config:
content: |
# Claude over ACP
This sandbox is a published *set*: one kit whose content was merged from
a shell base, Claude Code, and the Agent Client Protocol adapter. Run
`cat /usr/share/sandbox/kit/claude-acp-set/kit.yaml` to see the three, each pinned
by digest, and `ls /usr/share/sandbox/kit/` to see their own sources
staged beside each other.
Two ways to work here, and they are the same agent either way:
- Interactively, `claude` — the binary at `/usr/local/bin/claude`.
- Over ACP, `claude-agent-acp` on stdio, which an editor spawns and
speaks the protocol to. It execs the same binary, so a session driven
from an editor and one typed at the terminal share the version, the
credential, and the session-state volumes.
The adapter opens no sockets of its own. Its egress and its Anthropic
credential are the ones Claude Code already has, which is why the merged
network policy names `api.anthropic.com` once rather than twice.
directory: /home/agent/.claude
filename: CLAUDE.md
declarationBlocks:
- "3:0"
source:
kit: the set descriptor
path: capabilities[1]
args:
registry:
default: docker.io/docker
description: Registry namespace the listed kits were pushed to
pattern: ^[a-z0-9][a-z0-9._/:-]*$
buildArg: KIT_REGISTRY
kits:
- ref: docker.io/docker/sbx-kit-shell:1.0.0
digest: sha256:489eda82d62f015a1fe9456c897a672e6142b1765595cf1eb8b66098542d04e2
- ref: docker.io/docker/sbx-kit-claude-mixin:2.1.311
digest: sha256:fac7aed5b057487c9a516e152b9a107a76be7997681e33da1b74ca633d2b8f64
- ref: docker.io/docker/sbx-kit-claude-acp:0.97.0
digest: sha256:3f4d8cd25f7641d22460a7596e70e64ece73a3b4abc2c7b4f487d6501260ed37