Claude in a box
Why?
- Use it however you want: Run Claude from your terminal as a CLI, or drop it into an existing Docker Compose stack as a service.
- No API key, no extra billing: claudebox uses your existing Claude subscription and authenticates with your current Claude credentials, so personal use feels seamless.
- Real agent, strong isolation: Claude gets its full toolset inside the container—file editing, shell access, code analysis, and more; without access to your host machine or the open internet beyond Anthropic’s APIs.
Prerequisites
- Docker — Install Docker Desktop
- Claude CLI — installed and authenticated (
curl -fsSL https://claude.ai/install.sh | bash, then runclaudeonce to log in)
claudebox uses your Claude subscription. It reads local credentials (Keychain on macOS, ~/.claude/.credentials.json on Linux) to authenticate inside the container. Credentials are resolved in order: CLAUDE_CODE_OAUTH_TOKEN env var, then platform credential store.
Use as a CLI tool
For: running prompts and agentic tasks in a sandboxed container from your terminal.
Install
curl -fsSL https://raw.githubusercontent.com/ArmanJR/claudebox/main/install.sh | bashUsage
claudebox prompt "explain how DNS works" # run a single prompt claudebox prompt --json "explain DNS" # full JSON output claudebox prompt --verbose "explain DNS" # container logs + output claudebox server # start the HTTP API server claudebox server --openai # start with OpenAI-compatible API claudebox stop # stop the server claudebox logs # view server logs claudebox status # check if server is running claudebox version # show CLI version claudebox update # update the CLI
Works on macOS and Linux. Handles authentication automatically and refreshes expired tokens before launching the container.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
CLAUDEBOX_PORT |
3000 |
Host port |
CLAUDEBOX_IMAGE |
ghcr.io/armanjr/claudebox:latest |
Docker image |
CLAUDEBOX_NAME |
claudebox |
Container name |
CLAUDE_CODE_OAUTH_TOKEN |
— | Skip auto-detection, use this token directly |
CLAUDEBOX_API_KEY |
— | API key for /v1/* endpoints (used with --openai) |
Use as a service
For: adding Claude as an agent alongside other services in your Docker Compose stack.
Add to your docker-compose.yml
First, extract your OAuth token (re-run when it expires):
curl -fsSL https://raw.githubusercontent.com/ArmanJR/claudebox/main/setup-auth.sh | bashservices: claudebox: image: ghcr.io/armanjr/claudebox:latest cap_add: - NET_ADMIN ports: - "3000:3000" env_file: - path: .env.claude required: true
Then docker compose up -d. Other services in the same network reach Claude at http://claudebox:3000.
HTTP API
POST /prompt
Send a prompt to Claude and get a JSON response.
{
"prompt": "your prompt here",
"options": {
"model": "sonnet",
"maxTurns": 10,
"maxBudgetUsd": 1.0,
"systemPrompt": "you are a helpful assistant",
"appendSystemPrompt": "additional instructions",
"allowedTools": ["Read", "Edit", "Bash"],
"cwd": "/workspace"
}
}All fields in options are optional.
Response: Claude Code's JSON output (includes result, session_id, usage, total_cost_usd, etc.)
GET /health
Returns {"status": "ok", "activeRequests": 0}.
Server environment variables
| Variable | Default | Purpose |
|---|---|---|
PORT |
3000 |
Server listen port |
MAX_CONCURRENT |
4 |
Max parallel Claude processes |
OPENAI_COMPAT |
— | Set to 1 to enable /v1/* routes (set automatically by --openai) |
CLAUDEBOX_API_KEY |
— | If set, all /v1/* requests require Authorization: Bearer <key> |
OpenAI-compatible API
Start the server with --openai (CLI) or set OPENAI_COMPAT=1 (Docker) to expose /v1/chat/completions and /v1/models. This lets you use claudebox with any OpenAI-compatible client.
# CLI claudebox server --openai # Docker Compose — add to environment OPENAI_COMPAT=1
POST /v1/chat/completions
Accepts the standard OpenAI chat completions request format and translates it to Claude Code invocations.
curl http://localhost:3000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "sonnet", "messages": [ {"role": "system", "content": "You are a helpful assistant"}, {"role": "user", "content": "Explain DNS in one sentence"} ] }'
Returns a standard OpenAI-shaped response:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "sonnet",
"choices": [{
"index": 0,
"message": {"role": "assistant", "content": "..."},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": 100, "completion_tokens": 50, "total_tokens": 150}
}Supported features:
| Feature | How it maps |
|---|---|
messages[role=system] |
Concatenated into --system-prompt |
| Multi-turn conversation | Serialized into structured prompt with history |
model |
Passed through to Claude (sonnet, opus, haiku, or full model IDs) |
response_format (json_schema / json_object) |
Injected into prompt + validated; retries once on failure |
Base64 images (data:image/...;base64,...) |
Decoded to temp files, read by Claude's Read tool |
Not supported: streaming, function calling / tools, external image URLs, temperature / top_p, n > 1.
GET /v1/models
Lists available Claude models.
Authentication
If CLAUDEBOX_API_KEY is set, all /v1/* requests must include Authorization: Bearer <key>. The existing /prompt and /health endpoints are unaffected.
How It Works
Network isolation — iptables firewall blocks all outbound traffic except Anthropic API domains (baked into the image). To allow additional domains, mount a custom allowlist:
-v /path/to/allowed-domains.txt:/etc/allowed-domains.txt:ro
Workspace — /workspace is writable so Claude can create and edit files. Mount context files read-only at /workspace/context for reference (put your CLAUDE.md there).
Limitations
IP-based firewall — Domain allowlisting resolves IPs at container start. If Anthropic's CDN/load-balancer IPs rotate during the container's lifetime, connections will fail. Restart the container to re-resolve. This is an inherent limitation of iptables-based filtering.
Building Locally
docker compose up -d --build
To pin a specific Claude Code version:
docker compose build --build-arg CLAUDE_CODE_VERSION=2.1.80
License
MIT