Devcontainer Comparison: Anthropic Reference vs. ai-capabilities
24 May 2026
Compared 2026-05-24. Anthropic reference from claude-code/.devcontainer and docs.
Architecture
| Aspect | Anthropic Reference | This Project |
|---|---|---|
| Base image | node:20 | python:3.13-bookworm |
| Composition | Single container, standalone Dockerfile | Docker Compose: sandbox + proxy sidecar |
| Network isolation | iptables firewall inside the container (init-firewall.sh) | Separate proxy container (tinyproxy) on internal Docker network |
| Capabilities | Requires NET_ADMIN + NET_RAW (runArgs) | No extra capabilities needed |
| Shell | Zsh with Powerlevel10k, fzf, persistent history | Bash (no shell customization) |
| User | node (built-in from base image) | sandbox (created via useradd) |
The firewall approach is the biggest architectural difference. Anthropic uses iptables+ipset inside the container, which requires CAP_NET_ADMIN/CAP_NET_RAW — elevated privileges that some security teams disallow. The proxy sidecar approach is arguably more principled: the sandbox container has zero direct internet access (Docker internal network), and traffic must flow through a separate container enforcing the allowlist. This is defense-in-depth — even if someone bypasses tinyproxy config, the Docker network topology prevents direct egress.
Dev Container Feature
Anthropic now recommends using their Dev Container Feature rather than a custom Dockerfile:
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
}
}
This project installs Claude Code manually via npm install -g @anthropic-ai/claude-code in the Dockerfile. The Feature approach would simplify that step, but since the project needs Python 3.13 + uv + the proxy topology, the custom Dockerfile is the right call — the Feature is really for simpler setups.
Credential/Config Persistence
| Aspect | Anthropic Reference | This Project |
|---|---|---|
| ~/.claude | Named Docker volume (claude-code-config-${devcontainerId}) | Fine-grained bind mounts from ~/.claude-sandbox/ |
| Auth | Entire ~/.claude in one volume | Single .credentials.json bind mount |
| Settings | Bundled in the volume | Read-only mounts from ~/.myai/dotclaude/ |
| Per-project isolation | ${devcontainerId} in volume name | Directory structure under ~/.claude-sandbox/ai-capabilities/ |
The bind-mount strategy is more granular and more secure. Anthropic mounts the entire ~/.claude as one volume. This project mounts individual files read-only (settings, commands, skills, hooks) and only makes credentials and per-project data writable. This means the sandbox can’t accidentally modify the host’s Claude configuration. The tradeoff is more lines in docker-compose.yml to maintain.
Domain Allowlist Coverage
| Domain | Anthropic | This Project |
|---|---|---|
| Anthropic/Claude | Yes | Yes |
| Sentry | Yes | Yes |
| GitHub | Yes (IPs via API) | Yes (regex) |
| npm | Yes | Yes |
| VS Code marketplace | Yes | Yes |
| Statsig | Yes | No |
| Linear MCP | No | Yes |
| PyPI | No | Yes |
| OpenAI / Google | No | Yes |
| Go / Rust registries | No | Yes |
Anthropic’s firewall allowlists at the IP level (resolves DNS, adds IPs to ipset), so it catches CDN IP changes poorly. The regex-based hostname matching via tinyproxy is more robust for domains behind CDNs.
The project allowlist is broader because it calls multiple AI vendor APIs, while Anthropic’s reference only needs Claude.
Missing from the project allowlist: statsig.com and statsig.anthropic.com — used by Claude Code for feature flags. If Claude Code ever behaves oddly (features not enabling), this could be why. Though DISABLE_AUTOUPDATER=1 is set, reducing the impact.
Things Anthropic Does That This Project Doesn’t
NODE_OPTIONS=--max-old-space-size=4096— avoids OOM in long Claude Code sessions. Worth adding if crashes have been observed.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1— mentioned in docs for org policy. Not set here but could be, since the proxy already blocks non-essential domains.- Managed settings via
/etc/claude-code/managed-settings.json— recommended path for enforcing org policy. Not relevant for a personal project. git-delta— nice diff viewer. Low-priority nicety.- Persistent shell history — Anthropic mounts a volume for bash history. This sandbox loses history on restart.
Things This Project Does That Anthropic Doesn’t
- Proxy sidecar — cleaner network isolation without elevated capabilities.
- Entrypoint script — auto-runs
uv sync, fixes git remotes, configures MCP, prints integration status. Anthropic’s container has none of this automation. - Dual-mode launch — devcontainer mode vs. CLI mode in the entrypoint. Anthropic’s reference only targets VSCode devcontainers.
CLAUDE.md/ skills / hooks — read-only mounts of personal config. Anthropic’s reference is a blank slate.- Multi-vendor API keys —
.envfile with Anthropic/OpenAI/Gemini keys. Anthropic’s reference only handles Anthropic auth.
Recommendations
- Add
NODE_OPTIONS=--max-old-space-size=4096to docker-compose environment — prevents Node.js OOM in long sessions. - Add
statsig.anthropic.comandstatsig.comto the proxy allowlist for Claude Code feature flags. - No need to switch to the Dev Container Feature — the custom Dockerfile gives Python/uv/proxy integration that the Feature can’t provide.
- The proxy approach is better than Anthropic’s iptables approach for a Docker Compose setup — no elevated capabilities needed, and the separation of concerns is cleaner. Keep it.
- Shell history persistence is a low-effort quality-of-life add for interactive
sandbox-shelluse. Add a volume mount for/home/sandbox/.bash_history.