~/work/ccc-claude-code-container-sandboxed-ai-agent-workflow.md
Case study

CCC: Claude Code Container – Sandboxed AI Agent Workflow

A Docker-based Claude Code setup that gives the agent unrestricted reach inside the container while gating every edge onto the host through a lightweight safety layer — practical day-to-day agent autonomy, not theoretical.

role
Solo · personal tooling
sector
AI tooling · Claude Code workflow · agent safety
stack
Docker · Claude Code · MCP (host-exec) · mcp-proxy · Haiku · Bash
status
● in daily use · closed source for now
01 / Problem

Between YOLO and friction

Two defaults, both bad. Running Claude Code with --dangerously-skip-permissions ("YOLO") lets the agent move fast, but it has unrestricted access to your filesystem, network, and shell the moment it decides to use it. Running with the default permission prompts keeps you safe but turns routine agent work into a steady tap-tap of approvals. The right point on that spectrum depends on what the agent is actually doing — implementing a plan you already reviewed is not the same as researching the open web where prompt injection is a real concern.

02 / Architecture

Container is the blast radius

diagram · sandbox edgecontainer · host-exec · safety gate · host
container · sandbox host machine Claude Code YOLO inside full fs · net · shell project + config mounted at host paths safety gate Haiku risk check auto-approve low-risk UI popup for the rest approve · deny with reason host execution shell · files other MCPs via mcp-proxy (stdio → HTTP) host-exec approved
Claude runs unrestricted inside the container · host-exec is the only edge outward, gated by a Haiku risk check plus a UI approval fallback

Claude Code runs inside a Docker container (Ubuntu-based, auto-updating) with the YOLO flag set. Inside the container, the agent has whatever it needs — filesystem, network, shell — and doesn't have to ask. Outside the container, it has exactly one edge, and that edge is gated.

Path parity. Project files are mounted preserving their exact host paths, so there's no translation layer between what the agent sees and what exists on the host. /Volumes/Projects/foo is the same path inside the container as outside it.

Config parity. Claude's own configuration directory is mounted in as well, so hooks, slash commands, and preferences match the host. Moving between a host session and a container session doesn't change the agent's behavior.

03 / Safety gate

host-exec with a Haiku check

The only way the containerized agent reaches the host is through a custom MCP server called host-exec. Every call flows through a two-stage gate:

Stage one — AI risk check. A Haiku model evaluates the command against the working context and conservatively auto-approves low-risk operations (reads, lookups, benign tooling). A little latency, a lot of friction removed.

Stage two — UI popup. Anything that doesn't pass the AI check pops up a native approval dialog with the full command, a threat-score summary, and two buttons: approve, or deny with a reason the agent will see. The reason matters — it lets you push back without killing the run.

The container is the blast radius. Everything that crosses it is reviewed.
04 / Context-dependent trust

One toggle, two modes

The approval loop is the right default, but it's not always the right state. A toggle flips auto-approve on or off for the current container — either via a slash command inside Claude or through a small browser page on localhost. Implementing a reviewed plan? Auto-approve everything. Researching online where prompt injection is a live risk? Flip it off and let the gate catch every host call.

05 / Around the edges

Fleet, MCP routing, small details

Many CCCs at once. A local dashboard lists every running container on its port (3100–3115) with its own auto-approve toggle. Different projects run in parallel without stepping on each other.

MCP routing. Some MCPs live inside the container; others run on the host and are exposed to the containerized agent via mcp-proxy, a small stdio-to-HTTP bridge. Same tool surface either way, but no need to install host-side tooling inside every container.

Configuration. The current working directory is mounted automatically; additional paths can be added via a .cccrc file. Path parity between host and container turned out to be a practical win worth the small setup cost.

Sound hooks. Claude Code event hooks that play sounds use a CLI wrapper that plays directly on the host — or, when running inside the container, routes the sound playback through host-exec. One hook config, correct behavior in both places.

Worth noting: this isn't a foolproof agent-safety solution. It's a more practical point on the spectrum between no supervision and Claude Code's default permission system. For my day-to-day work, this balance has been the right one.

06 / Tech stack

Tools

  • Docker · Docker Compose
  • Claude Code (hooks · slash commands)
  • Custom MCP server (host-exec)
  • mcp-proxy (stdio ↔ HTTP)
  • Haiku (risk check)
  • Python · Bash
~/work
01 / 01 navigate · Esc close