sha256:3f48689bba9185d1d0244061cc189574b6c249e918c7aa50c3357565646bc4b1
Last pushed
5 days by cdupuis
Type
Sandbox Kit
Manifest digest
sha256:3f48689bba9185d1d0244061cc189574b6c249e918c7aa50c3357565646bc4b1
schemaVersion: "3"
displayName: Claude Code (mixin)
author: Docker, Inc.
description: The Claude Code CLI as a mixin — the native binary in an overlay, with the Anthropic credential (API key or claude.ai OAuth), session-state volumes, and the hooks the agent needs. Layer it onto a shell base and run `claude`.
sourceUrl: https://github.com/anthropics/claude-code
kind: mixin
provides:
- [email protected]
capabilities:
- 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
- type: com.docker.sandbox/credential@1
optional: true
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)
- type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/projects
size: 2g
description: Conversation history; grows without bound, gets the headroom
- type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/sessions
size: 512m
description: Per-session state; load-bearing for `claude -c`
- type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/todos
size: 512m
description: TodoWrite state
- type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/shell-snapshots
size: 512m
description: Bash state snapshots across sessions
- type: com.docker.sandbox/volume@1
config:
path: /home/agent/.claude/statsig
size: 512m
description: Local feature-flag cache
- 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='${{ kit.args.model }}'
effort='${{ kit.args.reasoningEffort }}'
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 sbx Desktop (see /usr/local/bin/sbx-claude-hook):
# Stop and StopFailure report a finished turn, Notification the
# moments Claude waits on the user. 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 ] } ],
\"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 sbx Desktop'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
- type: com.docker.sandbox/agent-skills@1
optional: true
config:
path: /home/agent/.claude/skills
- type: com.docker.sandbox/agent-context@1
config:
contentFile: /usr/share/sandbox/kit/claude-mixin/claude-context.md
directory: /home/agent/.claude
filename: CLAUDE.md
args:
model:
default: ""
description: Claude model to use (settings.json `model`); empty keeps the CLI default
pattern: ^[A-Za-z0-9._-]*$
env: CLAUDE_MODEL
reasoningEffort:
default: ""
description: Effort level (settings.json `effortLevel`); empty keeps the CLI default
enum:
- ""
- low
- medium
- high
- xhigh
- max
- auto
env: CLAUDE_REASONING_EFFORT
version:
default: 2.1.291
description: Claude Code release to install
pattern: ^[0-9]+\.[0-9]+\.[0-9]+$
buildArg: CLAUDE_VERSION