Sign inSign up

sbx/claude:latest

Cloud
Multi-platform
Manifest digest

sha256:611f52fac7bfc5fac443802588b490dda463d219b5d35e0b7087156e29d1ef10

Last pushed

about 6 hours by dhibot

Type

Sandbox Kit

Manifest digest

sha256:611f52fac7bfc5fac443802588b490dda463d219b5d35e0b7087156e29d1ef10

yaml
schemaVersion: "3"
displayName: Claude Code
author: Docker, Inc. https://docker.com
description: Anthropic's Claude Code agent on Docker Hardened Images
sourceUrl: https://github.com/docker-hardened-images/definitions
version: 2.1.318
licenses:
    - SEE LICENSE IN https://github.com/anthropics/claude-code/blob/main/LICENSE.md
kind: workload
provides:
    - [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@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/iputils-ping@20240905
    - 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]
capabilities:
    - type: com.docker.sandbox/sbx@1
    - 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
                - deb.debian.org:80
                - dhi.io:80
    - type: com.docker.sandbox/credential@1
      name: Anthropic access
      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
        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/agent-sessions@1
      config:
        continue:
            - --continue
        list:
            - python3
            - /opt/claude-sessions/interactive-sessions.py
        prompt:
            - -p
            - --
            - '{{.Prompt}}'
        resume:
            - --resume
            - '{{.SessionID}}'
      description: Drive claude sessions programmatically
    - type: com.docker.sandbox/agent-interactive-sessions@1
      optional: true
      config:
        continue:
            - --continue
        prompt:
            - --
            - '{{.Prompt}}'
        resume:
            - --resume
            - '{{.SessionID}}'
        sessionPicker:
            - --resume
      description: Open claude's terminal UI on a chosen session
    - 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,
                  \"hasSeenAutoDefaultNudge\": true,
                  \"projects\": { $projects }
                }" > /home/agent/.claude.json
                chown agent:agent /home/agent/.claude.json
              description: Seed Claude bypass/trust flags (root; overwrites image-shipped file)
              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 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
                export PATH="$HOME/.local/bin:$HOME/.claude/local:$PATH"
                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 (install-time, race-free)
              env:
                - MCP_GATEWAY_URL
                - MCP_SENTINEL_TOKEN_NAME
              user: agent
        startup:
            - background: true
              command:
                - sh
                - -c
                - command -v apt-get > /dev/null 2>&1 && (apt-get update -qq -y > /dev/null 2>&1 || true)
              description: Update apt package cache in background
              user: "0"
            - command: |
                set -e
                [ -n "$MCP_GATEWAY_URL" ] || exit 0
                export PATH="$HOME/.local/bin:$HOME/.claude/local:$PATH"
                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
      optional: true
      config:
        content: |
            ## Claude Code

            Claude Code is installed at `~/.local/bin/claude` by Anthropic's native installer. Launch is
            `claude --dangerously-skip-permissions`; the image entrypoint starts it. Run `claude` for an interactive session, or
            `claude -p "<prompt>"` for a one-shot run.

            Claude Code's permission prompts are turned off in `~/.claude/settings.json`
            (`permissions.defaultMode = "bypassPermissions"`). That is deliberate: the container is the sandbox, and a prompt
            nobody can answer just deadlocks a non-interactive session.

            Authentication is proxy-mediated. Depending on what the host has bound, either the `apiKeyHelper` in
            `~/.claude/settings.json` returns the literal string `proxy-managed` and the sandbox proxy substitutes the real
            Anthropic API key on requests to `api.anthropic.com`, or `~/.claude/.credentials.json` holds claude.ai OAuth tokens
            that are sentinels the proxy swaps at request time. Either way there is no real credential in this container. With
            nothing bound, `claude` will ask you to `/login`.

            Skills are read from `~/.claude/skills`, where the host's shared skills store mounts.

            ## Installing Packages

            The image ships a small toolset: shell and CLI tools, git, gh, Docker, and Python 3.14 with pip and uv. Install
            anything else with `sudo apt-get update && sudo apt-get install -y <package>`; `sudo` needs no password. Two apt
            repositories are configured and reachable through the sandbox proxy: Debian trixie (`deb.debian.org`) and Docker
            Hardened Images (`dhi.io/deb/debian/main`). The DHI repository carries versioned toolchains such as `golang-1.26`
            and `nodejs-24`; Debian supplies the rest, for example `default-jdk-headless`. `apt-cache search <term>` lists what
            is available. Building Python packages from source needs `build-essential` first.

            ## Environment Persistence

            The `CLAUDE_ENV_FILE` environment variable is set to `/etc/sandbox-persistent.sh`.

            According to [Claude Code Documentation](https://code.claude.com/docs/en/settings#bash-tool-behavior):

            > **CLAUDE_ENV_FILE**
            >
            > If set, this file will be sourced before each Bash command execution. This allows environment variables to persist
            > across multiple Bash tool invocations.

            This means `/etc/sandbox-persistent.sh` is sourced before every Bash tool call you make. Any `export` statements you
            append to this file will be available in all subsequent commands without needing a login shell.

            ### Shell Completions Must NOT Be in CLAUDE_ENV_FILE

            **NEVER add shell completion scripts to `/etc/sandbox-persistent.sh`.**

            `CLAUDE_ENV_FILE` is sourced **before every single bash command execution**, not just during shell initialization.
            Completion scripts rely on special variables (`COMP_WORDS`, `COMP_CWORD`, `COMPREPLY`) that only exist during
            tab-completion contexts.

            #### WRONG - Will Break Bash

            ```bash
            # DO NOT ADD THESE TO /etc/sandbox-persistent.sh
            [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
            [[ -s "$SDKMAN_DIR/etc/bash_completion.sh" ]] && source "$SDKMAN_DIR/etc/bash_completion.sh"
            ```

            #### CORRECT - Only Load Core Functionality

            ```bash
            # ONLY add the main initialization scripts
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

            export SDKMAN_DIR="$HOME/.sdkman"
            [[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ]] && source "$SDKMAN_DIR/bin/sdkman-init.sh"
            ```

            #### Symptoms of Broken Shell

            When completion scripts are incorrectly added:

            - All bash commands return no output (silent failure)
            - `echo`, `pwd`, and other basic commands produce no results
            - The bash tool becomes completely unusable

            #### Solution

            If you accidentally added completion scripts and broke the shell:

            1. Remove the completion line(s) from `/etc/sandbox-persistent.sh`
            1. Exit and restart the Claude Code session
            1. Verify with `echo "test"` that bash works again
        directory: /home/agent/.claude
        filename: CLAUDE.md
    - type: com.docker.sandbox/agent-context@2
      optional: true
      config:
        content: |
            ## Claude Code

            Claude Code is installed at `~/.local/bin/claude` by Anthropic's native installer. Launch is
            `claude --dangerously-skip-permissions`; the image entrypoint starts it. Run `claude` for an interactive session, or
            `claude -p "<prompt>"` for a one-shot run.

            Claude Code's permission prompts are turned off in `~/.claude/settings.json`
            (`permissions.defaultMode = "bypassPermissions"`). That is deliberate: the container is the sandbox, and a prompt
            nobody can answer just deadlocks a non-interactive session.

            Authentication is proxy-mediated. Depending on what the host has bound, either the `apiKeyHelper` in
            `~/.claude/settings.json` returns the literal string `proxy-managed` and the sandbox proxy substitutes the real
            Anthropic API key on requests to `api.anthropic.com`, or `~/.claude/.credentials.json` holds claude.ai OAuth tokens
            that are sentinels the proxy swaps at request time. Either way there is no real credential in this container. With
            nothing bound, `claude` will ask you to `/login`.

            Skills are read from `~/.claude/skills`, where the host's shared skills store mounts.

            ## Installing Packages

            The image ships a small toolset: shell and CLI tools, git, gh, Docker, and Python 3.14 with pip and uv. Install
            anything else with `sudo apt-get update && sudo apt-get install -y <package>`; `sudo` needs no password. Two apt
            repositories are configured and reachable through the sandbox proxy: Debian trixie (`deb.debian.org`) and Docker
            Hardened Images (`dhi.io/deb/debian/main`). The DHI repository carries versioned toolchains such as `golang-1.26`
            and `nodejs-24`; Debian supplies the rest, for example `default-jdk-headless`. `apt-cache search <term>` lists what
            is available. Building Python packages from source needs `build-essential` first.

            ## Environment Persistence

            The `CLAUDE_ENV_FILE` environment variable is set to `/etc/sandbox-persistent.sh`.

            According to [Claude Code Documentation](https://code.claude.com/docs/en/settings#bash-tool-behavior):

            > **CLAUDE_ENV_FILE**
            >
            > If set, this file will be sourced before each Bash command execution. This allows environment variables to persist
            > across multiple Bash tool invocations.

            This means `/etc/sandbox-persistent.sh` is sourced before every Bash tool call you make. Any `export` statements you
            append to this file will be available in all subsequent commands without needing a login shell.

            ### Shell Completions Must NOT Be in CLAUDE_ENV_FILE

            **NEVER add shell completion scripts to `/etc/sandbox-persistent.sh`.**

            `CLAUDE_ENV_FILE` is sourced **before every single bash command execution**, not just during shell initialization.
            Completion scripts rely on special variables (`COMP_WORDS`, `COMP_CWORD`, `COMPREPLY`) that only exist during
            tab-completion contexts.

            #### WRONG - Will Break Bash

            ```bash
            # DO NOT ADD THESE TO /etc/sandbox-persistent.sh
            [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
            [[ -s "$SDKMAN_DIR/etc/bash_completion.sh" ]] && source "$SDKMAN_DIR/etc/bash_completion.sh"
            ```

            #### CORRECT - Only Load Core Functionality

            ```bash
            # ONLY add the main initialization scripts
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

            export SDKMAN_DIR="$HOME/.sdkman"
            [[ -s "$SDKMAN_DIR/bin/sdkman-init.sh" ]] && source "$SDKMAN_DIR/bin/sdkman-init.sh"
            ```

            #### Symptoms of Broken Shell

            When completion scripts are incorrectly added:

            - All bash commands return no output (silent failure)
            - `echo`, `pwd`, and other basic commands produce no results
            - The bash tool becomes completely unusable

            #### Solution

            If you accidentally added completion scripts and broke the shell:

            1. Remove the completion line(s) from `/etc/sandbox-persistent.sh`
            1. Exit and restart the Claude Code session
            1. Verify with `echo "test"` that bash works again
        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:
        required: true
        description: Claude Code release the image carries
        pattern: ^[0-9]+\.[0-9]+\.[0-9]+$
        buildArg: VERSION