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. The machine and credentials determine 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 reach SSH keys and AWS profiles with real reach. It can also reach the macOS Keychain. The machine holds cloned repos full of uncommitted work. I keep permissions on and approve the destructive steps myself. I use herdr to manage the parallel sessions. The safety boundary comes from the permissions underneath it.
The micros are for work where supervision isn’t worth my attention. They run the same tools. A mistake starts from a box with much less access and no irreplaceable local state.
What makes the micros disposable # #
Pi runs tool actions with the permissions of its process and does not ask before each one. On the micros, I run Claude Code with --dangerously-skip-permissions
for the same unattended workflow. An agent can work through a task without stopping at every file edit or shell command. With three or four sessions running, permission prompts keep pulling me towards whichever window is asking. After enough routine approvals, I start approving them without reading closely, which makes the safety check less useful.
I would rather spend that attention checking the finished diff and deciding whether the approach is sound. Removing the prompts makes parallel work practical, but it also removes my chance to stop a bad command before it runs. That is why I only do it on machines with scoped credentials and replaceable local state.
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 are no 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. If the agent wipes the working tree, I rebuild the box from the configs repo and clone the branch again.
What the micros can still damage # #
Rebuilding the machine does not revoke the access I gave it. The agent can still push through whatever Git credentials are available, and the dev AWS role can still change resources inside its project. A reflash does not undo remote damage.
The coding tools need outbound internet access to do the job. That includes the model APIs and the project’s external dependencies. Tailscale removes public ingress. It does not make arbitrary outbound access safe, so I do not put production credentials or personal secrets on these boxes.
The result is a smaller failure domain. I do not 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. In auto-allow mode, commands that stay within its filesystem and network limits can run without asking each time. It uses Seatbelt on macOS and bubblewrap on Linux. By default, sandboxed Bash can still read most of the machine, including credential files, unless those paths are denied. Claude’s built-in file tools use its permission system directly rather than running through the sandbox.
Pi does not 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 reach. The agent would still need 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 have no public ingress. They sit on my tailnet with no forwarded ports and no exposed SSH, so there is nothing public to scan. Tailscale ACLs restrict which of my devices can reach them, and Tailscale SSH handles authentication without long-lived SSH keys on the runners.
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. Tailscale controls who can reach the runners. The AWS role and Git credentials control what the agents can reach from them.
## When the extra caution is worth it [#](#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 does not remove credential risk. If a project credential leaks, I still have to revoke it and inspect what it touched. The box keeps valuable local state out of that incident, and the AWS role limits the cloud damage to dev. It does nothing for systems the leaked project credential can reach, so the remaining cost depends on how tightly I scoped it.
What matters is where the caution lives. A sentence in an instruction file and your own attention are weak controls compared with limited credentials and replaceable local state. If a box needs a credential, assume the agent can expose it and scope it accordingly.