AI workspace isolation
A safe place to experiment with autonomous coding agents: each one gets its own isolated workspace, its own credentials, and nothing of mine it doesn't need.
Why
The project started the first time I watched Claude ask to go looking through my home folder for passwords. It was asking, not doing, but it was enough. I knew I didn't want agents running on my machine without real isolation.
First attempt: wrappers
My first move was to put wrappers around the commands an agent could
use. git-auto could commit but not push. jira-auto
allowed only a handful of Jira commands.
It worked, up to a point. When I wanted the agent to have its own git credentials, separate from mine, I hit a wall: tools look for credentials in the home folder, and the agent shared my home folder. More to the point, wrappers limit what an agent is supposed to do. They don't stop it reading anything else on the machine. That isn't isolation.
Containers
So each workspace became a Docker container. The popular coding harnesses are baked in (Claude Code, Codex and OpenCode), and the agent gets a home folder of its own, with its own git identity.
- One durable folder. The workspace is a single folder bind-mounted from the host. Everything else, home folder included, is disposable and reset on every start.
- Its own identity. The agent commits as davidjk-agent, a GitHub account separate from my own, so its work is always attributable.
- Read-only reference. Material I want the agent to see but never change is mounted read-only. The kernel enforces it.
Talking to it
Isolation is only half the problem. I also needed a way to work with the agents and to leave sessions running. So I added tmux for persistent sessions, then put the terminals in the browser with ttyd, behind a small web server inside the container.
/workspace outlives the container.The viewers
Once Caddy was in place, I split the browser page in two: the agent's terminal below, and a pane above showing a file from the workspace. The pane checks the file with a lightweight HEAD request every couple of seconds and reloads when it changes, so edits show up as they land. The agent can drive the pane itself, opening whatever it wants me to look at.
Then came custom viewers: rendered Markdown, highlighted source code with line numbers, and draw.io diagrams. HTML pages render as they are. And because the file server can also answer with JSON, an agent can build a single-page HTML app that reads its data straight from the workspace.
That changed how I work. Now I can dictate to Claude or Codex and watch them work on my diagram live.
Still to write
- Multi-site, tailnet, and always-on environments.
- How secrets reach a workspace without ever being committed.
- Running several workspaces side by side, each with its own ports.
- What I'd do differently.