Claude Code in a Docker image built on aicodebox, with an HTTP API, an OpenAI-compatible endpoint...
10K+
A runtime harness for Claude Code, the agentic coding CLI from Anthropic. The standard wrapper runs Claude in Docker with a mounted workspace, persistent Claude and SSH state, passwordless sudo, the host Docker socket, and --permission-mode bypassPermissions enabled by default.
v2.0.0 — rebased on
psyb0t/aicodebox. claudebox is now a thin child image of the shared aicodebox base (same pattern aspsyb0t/pibox). Every mode surface (API / Telegram / Cron / MCP) is inherited from the base and stays in lockstep with future base fixes. SeeCHANGELOG.md for the full migration guide (endpoint shape changes, env-var namespace, path renames — all mitigated by aliases + symlinks so existing configs keep working).
Host boundary: this is not a sandbox for untrusted prompts. The standard wrapper mounts /var/run/docker.sock, so Claude can control the host Docker daemon. The server Compose examples omit it. Keep the socket out of server deployments unless the workload needs that authority. Use memory, CPU, PID, and log limits for long running containers. The current image installs Claude Code on first start and changes its runtime identity during boot, so do not add read_only: true or drop all capabilities unless you have tested that exact image and launch path.
claudebox wraps Claude Code with several distinct interfaces:
claude command, with persistent containers and automatic session resumption across runschat/completions adapter that lets LiteLLM, OpenAI SDKs, and any OpenAI-compatible client talk to Claude Code, complete with streaming SSE, multi-turn conversations, and multimodal image handlingBeyond just running Claude Code in Docker, claudebox adds skill injection (auto-load SKILL.md files into every session), init hooks, custom script directories, structured JSON logging, and a workspace management layer that handles multi-tenant isolation with automatic busy/idle tracking.
Renamed from
docker-claude-code: This project was previously calleddocker-claude-codewith the Docker image atpsyb0t/claude-code. Starting with v1.0.0, it isclaudebox— the Docker image is nowpsyb0t/claudebox, the default binary name isclaudebox, the GitHub repository ispsyb0t/docker-claudebox, and the SSH key directory defaults to~/.ssh/claudebox. If you were using the old names, update your image references, wrapper scripts, and SSH paths accordingly.
claudebox wrapperDocker installed and running. That's it.
The install script pulls the Docker image, generates SSH keys for git operations inside the container, downloads the wrapper script, and installs it as a command on your system.
# minimal image — default; Claude installs what it needs on the fly
curl -fsSL https://raw.githubusercontent.com/psyb0t/docker-claudebox/master/install.sh | bash
# full image — every dev tool pre-installed (Go, Python, kubectl, terraform, ...)
export CLAUDEBOX_FULL=1 && curl -fsSL https://raw.githubusercontent.com/psyb0t/docker-claudebox/master/install.sh | bash
# custom binary name (e.g. if you want to call it 'claude' instead of 'claudebox')
curl -fsSL https://raw.githubusercontent.com/psyb0t/docker-claudebox/master/install.sh | bash -s -- claude
# or: export CLAUDEBOX_BIN_NAME=claude && curl -fsSL .../install.sh | bash
v2 note: the variant naming flipped in v2.
latestis now the minimal image (was the full image pre-v2);latest-fullis the toolchain-loaded variant (waslatestpre-v2). TheCLAUDEBOX_MINIMAL=1opt-in from v1 is now a no-op — you already get minimal by default. SetCLAUDEBOX_FULL=1to opt into the toolchain image. Installing withCLAUDEBOX_FULL=1(as above) bakes the choice into the installed wrapper, so the full variant sticks for every run — you don't need to keep the env var set afterward.
The remote installer downloads wrapper.sh from its matching release tag.
Automation can set CLAUDEBOX_INSTALL_DIR, CLAUDEBOX_BIN_NAME, and
AICODEBOX_MANAGED_INSTALL=1 when it installs into a different command
directory without prompting to replace an existing SSH key.
Heads up on env vars:
VAR=x curl … | bashdoes not setVARfor the install script — bash semantics attach the var tocurlonly. Alwaysexportthe var first (or put it on thebashside of the pipe).
If you prefer not to pipe scripts to bash:
# 1. create the data directory
mkdir -p ~/.claude
# 2. create SSH keys for git operations inside the container
mkdir -p "$HOME/.ssh/claudebox"
ssh-keygen -t ed25519 -C "[email protected]" -f "$HOME/.ssh/claudebox/id_ed25519" -N ""
# then add the public key to GitHub/GitLab/wherever you push code
# 3. pull the image
docker pull psyb0t/claudebox:latest # minimal (default)
# or: docker pull psyb0t/claudebox:latest-full # toolchain-loaded variant
# 4. grab the wrapper script and install it
# see install.sh for exactly how the wrapper is set up
claudebox wrapperRun claudebox from the directory you want Claude to work in. The wrapper
mounts that directory at the same absolute path inside the container, persists
~/.claude and ~/.ssh/claudebox, and resumes the directory's interactive
session by default.
claudebox # interactive Claude in this directory
claudebox --no-continue # interactive session without resuming
claudebox -p "explain this codebase" # one prompt, then exit
claudebox setup-token # save OAuth credentials in ~/.claude
claudebox doctor # passthrough to Claude Code diagnostics
claudebox --version # passthrough to Claude Code
claudebox stop # stop this directory's running container
claudebox clear-session # remove saved sessions, keep auth/config
Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN on the host for a run, or
use claudebox setup-token once. Use claudebox -p "prompt" for a direct
programmatic run. See Configuration for CLAUDEBOX_ENV_*,
CLAUDEBOX_MOUNT_*, image selection, and mode settings.
The installed wrapper is the normal interface for people and agents. An agent
should run claudebox from the requested workspace instead of constructing a
new docker run command. The wrapper preserves the workspace path, Claude
state, SSH state, image choice, and container lifecycle.
claudebox -p "inspect this workspace and report the failing tests"
CLAUDEBOX_FULL=1 claudebox -p "run the full test suite"
claudebox -p "emit machine-readable events" --output-format stream-json
When one box needs another, install claudebox, codexbox, and pibox in
the same command directory. A running box can call the sibling command
directly. The parent wrapper passes the host launch context and mounts only
the sibling wrapper file. Do not set AICODEBOX_HOST_*, copy a wrapper, or
manually mount another box's state directory.
psyb0t/claudebox:latest (minimal, default)The default v2 image. Just enough to run Claude Code on top of the aicodebox base: Ubuntu 24.04, git/curl/wget/jq, Node.js 24 LTS + npm, Python 3.14 + uv, Docker CE. Claude has passwordless sudo, so it will install whatever else it needs on the fly via apt-get, pip, npm, etc. Smaller image, faster pull, first run may take longer while Claude sorts out its own tooling.
Claude Code is installed on first run, not baked into the image. Anthropic's Claude Code CLI is proprietary and can't be redistributed, so the image ships only the pinned version (
CLAUDEBOX_CLAUDE_VERSION, default set at build) and the entrypoint runsnpm install -g @anthropic-ai/claude-code@<version>from npm the first time a fresh container starts. This means the published image redistributes none of Anthropic's software, and each container pulls Claude Code straight from npm. First container start needs network and takes a few extra seconds; warm restarts skip it. To pin a different version, setCLAUDEBOX_CLAUDE_VERSIONatdocker run.
curl -fsSL https://raw.githubusercontent.com/psyb0t/docker-claudebox/master/install.sh | bash
Use /aicodebox-init.d/*.sh hooks (see Init Hooks) to pre-install your tools on first container create so Claude doesn't burn tokens figuring out package management.
psyb0t/claudebox:latest-full (toolchain-loaded)Everything pre-installed. This variant starts from the immutable aicodebox:v0.17.0-full base, then adds only Claude-specific code. Aicodebox owns the shared Go, Python, Node, C/C++, DevOps, database, editor, and diagnostic toolchain; claudebox stays ready without rebuilding that stack.
export CLAUDEBOX_FULL=1 && curl -fsSL https://raw.githubusercontent.com/psyb0t/docker-claudebox/master/install.sh | bash
latest (minimal) | latest-full | |
|---|---|---|
| Ubuntu 24.04 | yes | yes |
| git, curl, wget, jq | yes | yes |
| Node.js LTS + npm | yes | yes |
| Docker CE + Compose | yes | yes |
| Claude Code CLI | yes | yes |
| Go 1.26.8 + tools | - | yes |
| Python 3.14.7 + tools | - | yes |
| Node.js dev tools | - | yes |
| C/C++ tools | - | yes |
| DevOps (terraform, kubectl, helm, gh) | - | yes |
| Database clients | - | yes |
| Shell utilities (ripgrep, bat, etc.) | - | yes |
The shared toolchain is defined and released by aicodebox. Claudebox adds its own adapter, init hooks, configuration, and first-run Claude Code installation on top.
Languages and runtimes:
DevOps and infrastructure:
gh)Database clients:
psql), mysql-client, redis-tools (redis-cli)Shell and system utilities:
Container automation:
CLAUDE.md in each workspace listing all available tools, so Claude knows what it has access to--update)~/.claude/bin (added to PATH automatically)~/.claude/init.d/*.sh (run once on first container create)~/.claude/.always-skills/ (injected into every invocation)--continue / --no-continue / --resume <session_id>DEBUG=trueYou need either an Anthropic API key or an OAuth token. Set up once, use everywhere:
# interactive OAuth token setup (one-time)
claudebox setup-token
# then use the token for programmatic and headless runs
CLAUDE_CODE_OAUTH_TOKEN=your-oauth-token claudebox -p "do stuff"
# or use an API key directly
ANTHROPIC_API_KEY=your-api-key claudebox -p "do stuff"
claudebox can run in several modes — pick the one that matches how you want to use Claude Code. Each has its own page with full setup, env vars, and examples.
Drop-in replacement for claude. Persistent per-workspace container, automatic session resumption, plus utility commands like claudebox doctor, claudebox mcp list, claudebox stop, and claudebox clear-session.
claudebox
Non-interactive prompt → response for scripts, pipelines, and automation. Plain text, JSON, and native stream-json output formats. Model selection, system prompt overrides, JSON-schema-constrained output, and session continuation. For a stable full-event response, use API mode with eventMode: "full".
claudebox -p "explain this codebase" --output-format json --model haiku
Run as a long-lived HTTP server. Full REST API for prompts and file ops with workspace isolation, async runs with run-id polling, OpenAI-compatible chat/completions endpoint (streaming + multimodal + LiteLLM compatible), and an MCP endpoint over streamable HTTP so other agents can use Claude Code as a tool.
environment:
- CLAUDEBOX_API_MODE=1
- CLAUDEBOX_API_MODE_TOKEN=your-secret-token
Talk to Claude from Telegram. Per-chat isolated workspaces, configurable models, effort, and system prompts, explicit chat and group user access control, file, photo, video, and voice ingestion, /fetch, /cancel, /status, /config, and /reload commands, plus [SEND_FILE: path] for Claude to send files back.
environment:
- CLAUDEBOX_TELEGRAM_MODE=1
- CLAUDEBOX_TELEGRAM_MODE_TOKEN=...
YAML defined scheduled jobs. Use five field cron for minute resolution or six field cron for second resolution. Per-job artifacts live under $HOME/.aicodebox/cron/history/, docker logs shows each tick, and same-name overlaps are skipped. Set root defaults and override them per job as needed.
environment:
- CLAUDEBOX_CRON_MODE=1
- CLAUDEBOX_CRON_MODE_FILE=/home/aicode/.aicodebox/cron.yaml
Expose Claude Code as an MCP server over streamable HTTP so other agents can drive it as a tool through run_prompt and workspace-confined file tools. MCP is not a foreground mode. With CLAUDEBOX_MCP_MODE=1, it mounts at /mcp/ in API mode or runs as a sidecar on its own port with Telegram, cron, or interactive mode.
environment:
- CLAUDEBOX_MCP_MODE=1
- CLAUDEBOX_MCP_MODE_TOKEN=your-secret-token
CLAUDEBOX_* settings the wrapper and entrypoint understand, plus CLAUDEBOX_ENV_* (forward arbitrary vars into the container) and CLAUDEBOX_MOUNT_* (extra volume mounts).~/.claude/bin), one-time init hooks (~/.claude/init.d), always-active skills auto-injected into every session (~/.claude/.always-skills), and MCP server definitions (project .mcp.json or global ~/.claude.json).Install claudebox, codexbox, and pibox in the same command directory,
normally /usr/local/bin, when one box needs to launch another. The wrapper
finds sibling wrapper files there and mounts them read-only into the container.
A sibling wrapper then runs through the host Docker daemon and mounts its own
host data directory. Claudebox does not directly mount another agent's home.
AICODEBOX_HOST_* is the versioned nested-launch context used by sibling
wrappers. It records host bind-source paths and is set automatically by a
wrapper. Do not set it for an ordinary host launch.
The skill works in any agent that reads .agents/skills/. It tells agents to use the installed wrapper for local work and to use MCP only for an already-running remote server. It installs natively in the clients below.
claude plugin marketplace add psyb0t/agents
claude plugin install claudebox@psyb0t
Claude Code prompts for the claudebox server URL and, if the MCP surface has auth enabled, the bearer token — the token is stored in your OS keychain.
codex plugin marketplace add psyb0t/agents
codex plugin add claudebox@psyb0t
Installed via the marketplace, the skill invokes as $claudebox:claudebox. Codex also picks the skill up automatically, with no install, in any repo containing .agents/skills/ — there it invokes as plain $claudebox.
The skill is published to ClawHub on every release:
openclaw skills install @psyb0t/claudebox
For MCP clients that speak local stdio, the @psyb0t/claudebox plugin bridges to the service's /mcp/ endpoint:
openclaw plugins install clawhub:@psyb0t/claudebox
Then set CLAUDEBOX_URL (and CLAUDEBOX_MCP_MODE_TOKEN if the server requires auth).
--permission-mode bypassPermissions is the adapter's default (modern equivalent of the pre-v2 --dangerously-skip-permissions). Claude has full, unrestricted access to the container. That's the entire point. Override per-request via RunRequest.extra_args./home/you/project is mounted at the same path inside the container. This means Docker volume mounts that Claude creates from within the container resolve correctly against host paths.claude user UID/GID is automatically adjusted to match the host directory owner on startup. File permissions should just work without manual chown.claude-<path> for interactive (TTY) sessions and claude-<path>_prog for programmatic (no TTY) sessions. Both share the same mounted volumes and data.telegram.yml, TELEGRAM_CHAT_ID becomes the only allowed chat. If both are absent, the compatibility fallback permits every chat. Use an explicit allowed_chats list before exposing the bot.claudebox --update when you want to update.WTFPL — do what the fuck you want to.
Content type
Image
Digest
sha256:04020e27f…
Size
451.2 MB
Last updated
about 6 hours ago
docker pull psyb0t/claudebox