Where I run my coding agents, and why it depends on the box
I use Pi and Claude Code day to day, and I run them in two places. On my Mac, Claude Code’s permissions stay on because the box holds personal credentials and uncommitted work. On a pair of second-hand Dell micros, both agents run unattended with scoped project access and no irreplaceable local state.
I assume an unattended agent will eventually do something I didn’t mean, so the useful safety question is what that mistake can reach. Hooks and instruction files still help inside the session, but the machine and its credentials decide how much damage is possible.
Mac versus micro #
| MacBook Pro | Dell OptiPlex micros | |
|---|---|---|
| Agent permissions | Claude Code permissions on, with me in the loop | Pi without per-action prompts Claude Code with --dangerously-skip-permissions |
| Credentials | Personal SSH keys, AWS profiles and macOS Keychain | Project credentials and a scoped dev role, no personal keys |
| Working copy | May contain uncommitted work I care about | Disposable task branch |
| Recovery | Depends on what the agent reached | Reflash local state and revoke exposed credentials |
On my MacBook Pro, a mistake can get at personal SSH keys and AWS profiles that can change real accounts, plus whatever’s in the macOS Keychain, and the cloned repos are full of uncommitted work. So permissions stay on and I approve the destructive steps myself. I use herdr to manage the parallel sessions, but the safety boundary is the permission prompts underneath it.
The micros are for work where supervision isn’t worth my attention. They run the same tools, but a mistake there starts from a box with much less access and nothing on it I’d miss.
What makes the micros disposable #
With three or four sessions running, permission prompts keep pulling me towards whichever window is asking, and after enough routine approvals I start approving them without reading closely, which makes the safety check less useful. I’d rather spend that attention checking the finished diff and deciding whether the approach is sound.
So on the micros the prompts come off. Pi runs tool actions with the permissions of its process and doesn’t ask before each one, and I run Claude Code with --dangerously-skip-permissions for the same unattended workflow. The agent can work through a task without stopping at every file edit or shell command, and I lose my chance to stop a bad command before it runs, which is why I only do it on the micros.
I’ve got a couple of OptiPlex micros that exist purely as agent runners. Each one gets an AWS role limited to the dev account and the project it’s working on. There aren’t any personal keys on the box, and nothing on disk that I can’t rebuild from the configs repo inside twenty minutes.
The checkout lives on a task branch, so if the agent wipes the working tree I reflash and clone the branch again.
What the micros can still damage #
Rebuilding the machine doesn’t revoke the access I gave it. The agent can still push through whatever Git credentials are on the box, and the dev AWS role can still change resources inside its project, so a reflash doesn’t undo remote damage.
flowchart TD
M[Agent mistake on a micro] --> L[Local damage:<br/>wiped checkout, broken box]
M --> R[Remote damage:<br/>pushed commits, dev AWS changes]
L --> F[Reflash, clone the branch again]
R --> V[Revoke the credential,<br/>inspect what it touched]
The coding tools need outbound internet access to do the job, for the model APIs and the project’s external dependencies. Tailscale removes public ingress, but it doesn’t make arbitrary outbound access safe, so I don’t put production credentials or personal secrets on these boxes.
The result is a smaller failure domain. I don’t treat it as a sandbox for hostile code: Git permissions and the dev role are still part of the boundary, so I scope them separately from the machine.
Where sandboxes fit #
Claude Code has a native sandbox for Bash and its child processes (Seatbelt on macOS, bubblewrap on Linux), and in auto-allow mode, commands that stay within its filesystem and network limits can run without asking each time. By default, sandboxed Bash can still read most of the machine, including credential files, unless those paths are denied, and Claude’s built-in file tools use its permission system directly rather than running through the sandbox.
Pi doesn’t include a built-in sandbox. Its containerisation guide covers putting the whole process inside Docker or routing its tools through a Gondolin micro-VM.
The micros are the main boundary in this setup. Adding a sandbox would reduce what a bad command can get at, but the agent still needs a writable checkout and some project credentials, so the machine and credential limits underneath it stay the same.
Tailscale as the access boundary #
The micros sit on my tailnet with no forwarded ports and no exposed SSH, so there’s nothing public to scan. Tailscale ACLs restrict which of my devices can reach them, and Tailscale SSH handles authentication without long-lived keys on the runners; what the agents can do from the box comes down to the AWS role and Git credentials.
I drive the sessions through herdr --remote over that connection, so I can start a run from the laptop or check it from my phone without exposing another service.
When the extra caution is worth it #
For some work on the Mac, this is more caution than I need. Claude Code’s default permissions are already sensible, and most tasks I give it never go near anything destructive. Reviewing every edit on a small refactor buys me very little.
The micro doesn’t remove credential risk. If a project credential leaks I still have to revoke it and inspect what it touched; the box keeps my own keys and uncommitted work out of that incident, and the AWS role limits the cloud damage to dev. It does nothing for other systems the leaked credential can log into, so the remaining cost depends on how tightly I scoped it.
A sentence in an instruction file and your own attention are weak controls compared with limited credentials and a box you can reflash. If a box needs a credential, assume the agent can expose it and scope it accordingly.
Discussion