Letting go of the wheel

Running claude-container headless

The point of building a sandbox is to give you peace of mind once you stop watching what's going on in it. Until now I've supervised every session interactively, which gives some degree of observability, as in I was always sat there ready to hit Ctrl-C.

The container is already set up for batch usage though: it runs --rm so doesn't hold any state between runs, just whichever folder is passed as context.

The only thing making it interactive is stdin_open: true and tty: true in the Compose config, which I've so far inherited without questioning: why not try headless?

There is even the ability to resume a Claude Code session, so there's nothing stopping you switching between the two at will.

A third mode

Post 2 added --unrestricted-network by layering a second compose file over the base. Headless is the same move again, so the script now has three ways to run:

claude-container ~/repo                          # interactive, restricted
claude-container -n ~/repo                       # interactive, open
claude-container -p 'count the files' ~/repo     # headless, restricted

Overriding takes just four lines, because the rest is inherited from the compose.yml underneath:

services:
  claude-auth-workspace:
    tty: false
    stdin_open: false
    entrypoint: ["claude", "--dangerously-skip-permissions", "-p"]

Importantly here we set entrypoint rather than command so that podman compose run appends the prompt as a single trailing argument. The runner picks up a -p/--prompt flag, adds this file to the compose stack when it's set, and passes the prompt through.

The final line of Dockerfile.claude sets

CMD ["claude", "--dangerously-skip-permissions"]

When only CMD is set, Docker/Podman runs it via the image's default entrypoint, effectively as the whole command line. Setting entrypoint: in the Compose config here replaces that, and importantly resets the CMD to empty.

Headless

With this change, you can then just point the claude-container script at a given folder, with a given prompt, and not have to actually engage with Claude Code at all (having already set up the auth credentials etc. at login in an interactive session, and choice of model).

In this case I got a limerick written to file by Haiku, standard.

Logging egress for permissive network access

At this point I went back and changed what -n meant because the only time I could monitor egress logs was when locked down to just Anthropic's API servers. Obviously this was not ideal, because when the agent went to look up info on the open web I had no ability to audit where it had gone.

Instead, I changed it to be permissive yet still log the egress traffic, for instance in this query where I look up a supermarket opening hours and write them to disk it accessed:

2026/08/23 15:56:17| Accepting HTTP Socket connections at conn3 local=[::]:3128 remote=[::] FD 11 flags=9
    listening port: 3128
1787500578.712     70 10.89.0.29 TCP_TUNNEL/200 47795 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
2026/08/23 15:56:18| storeLateRelease: released 0 objects
1787500578.749     28 10.89.0.29 TCP_TUNNEL/200 44603 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500578.787     34 10.89.0.29 TCP_TUNNEL/200 43347 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500578.829     37 10.89.0.29 TCP_TUNNEL/200 16834 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500578.913    271 10.89.0.29 TCP_TUNNEL/200 3969 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500578.932    290 10.89.0.29 TCP_TUNNEL/200 4440 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500579.007    366 10.89.0.29 TCP_TUNNEL/200 4362 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500590.300    155 10.89.0.29 TCP_TUNNEL/200 3886 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500590.359     55 10.89.0.29 TCP_TUNNEL/200 8795 CONNECT www.tesco.com:443 - HIER_DIRECT/2.16.176.65 -
1787500592.689    141 10.89.0.29 TCP_TUNNEL/200 3900 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500596.115   3415 10.89.0.29 TCP_TUNNEL/200 22043 CONNECT www.supermarkethours.co.uk:443 - HIER_DIRECT/108.160.158.29 -
1787500601.980  23341 10.89.0.29 TCP_TUNNEL/200 52850 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
1787500601.980  23289 10.89.0.29 TCP_TUNNEL/200 7472 CONNECT api.anthropic.com:443 - HIER_DIRECT/160.79.104.10 -
Domain Count
api.anthropic.com 11
www.tesco.com 1
www.supermarkethours.co.uk 1

In comparison, asking a query in the restricted (default) mode sent 10 CONNECT requests to api.anthropic.com.

Simple beginnings

This still isn't orchestration: there's no retry, scheduling, nor state beyond the working directory, and no attempt to recover runs that die midway through.

What it is, is the minimum viable change that turns claude-container from an app you must sit in front of into a tool you can call in the background, or weave into an application. In other words this is just the doorway to more interesting applications.