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.

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:
- api.anthropic.com
- www.tesco.com
- www.supermarkethours.co.uk
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.