— 7 min read

"Cheap" agentic branches

After going back and forth, i have settled on a sandboxing approach for agent-assisted coding, a ~700 lines bash util for managing OrbStack containers (or Tart macOS VMs):

Branching an agentic sandbox brings along its full context, including databases and installed dependencies. So it’s not exactly “cheap”, but rather fast.

Requirements#

Agents operate at an incredible speed. For them to be effective, some requirements need to be met:

  • Context. The right context at the right time, nothing to steer in the wrong direction.
  • Loopable. The agent needs to be able to run and verify their solution. Including running tests and tapping buttons.
  • Freedom. If an agent attempts to install something you do not approve of, then the prompt was underspecified to begin with. Hand-holding an agent on each decision/command introduces an unnecessary bottle-neck.

You might have noticed that these requirements do not mention security or privacy at all. An agent does not require security to be efficient, but that requirement is mine. It is a fundamental concern to safeguard my own and my client’s data and intellectual property.

I have found myself concurrently managing a number of projects with different ranges of needs in confidentiality, regulatory concerns and room for error. For some projects, especially prototyping, I’m closer to vibe-coding. For others, every detail counts and some code can contractually not be exposed/leaked to any third party.

That means there is also a set of human requirements:

  • Security/Privacy. Agents should not have access to any credentials, personal data, or anything that is not strictly necessary for the task.
  • Separation of concerns. Managing several projects, an agent for one project has no business looking at other repositories, unless it serves the context requirement. Meaning one single sandbox is not enough.
  • Visibility. I don’t want any agent in my IDE, but I want to be able to look at the implementation directly in my IDE, to take edits directly.
  • Speed. It should be fast and efficient to point an agent at an idea. Similarly, discarding an idea should be instant. In git lingo, it should be cheap to branch.

The first item alone discards installing Claude Code on your host machine directly as an option.

The golden base to clone#

Running sandbox base creates a fresh debian-based OrbStack isolated machine, installs all dependencies from a setup.sh file and ensures that a coding agent is wired up (similar to a Dockerfile). From that moment, new containers can be created within seconds by cloning the base image and mounting a single workspace folder from the host machine:

$ sandbox new
ready: sandbox shell weathered-wave  (mode: Claude, backend: orb)

Agents can then build and run services that are accessible from the host, for example http://weathered-wave.orb.local:3000, so both IDE and browser can reach and review the work. Which is also why I landed on OrbStack rather than plain Docker, it behaves like a small VM.

Isolated OrbStack machines block access to the host, which I assumed included the local network. Quite surprised when the containers were able to reach my router at 192.168.1.1. For that reason, the setup script includes an egress firewall by adding a small nftables ruleset and each clone removes the sandbox user’s sudo, so agents can not circumvent it.

For self-hosted models, sandbox new --pi installs pi instead of Claude Code and sets up a reverse SSH tunnel, such that the sandbox can reach oMLX running on the host machine. It turned out that OrbStack’s built-in SSH server didn’t support reverse port forwarding, so each sandbox now runs its own SSH server and the host dials into that instead. I’ve been getting good results with Qwen3.6-35B-A3B-4bit and Qwen3.6-27B-MLX-8bit.

A --local flag takes this a step further and blocks outbound DNS as well (otherwise equivalent to --pi):

$ sandbox new --local
ready: sandbox shell icy-frog  (mode: Local, backend: orb)

$ sandbox shell icy-frog
marcel@icy-frog:/workspace$ curl -m 3 -sS -o /dev/null -w '%{http_code}\n' http://example.com
curl: (6) Could not resolve host: example.com
000

# agent has no privileges to edit firewall
marcel@icy-frog:/workspace$ sudo -n true
sudo: a password is required

On macOS, running “Low Power” energy mode reduces token generation (~63 tok/s vs. ~81 in automatic mode on Qwen3.6-35B), but produces noticeably less heat and fan noise.

This is great, but the inherent concern of a shared kernel among OrbStack containers remains and is mentioned in their own documentation:

“Isolated machines aren’t recommended for analyzing malware or running code that will actively try to exploit the kernel and escape the sandbox. For that, use a full virtual machine with its own kernel.”

Right now there is support for two backends:

$ sandbox base --macos
$ sandbox new --macos [--gui]
ready: sandbox shell bold-star  (mode: macOS, backend: tart)

The same pattern works with Tart VMs. Cloning a macOS virtual machine will take a bit longer and require more disk space (~80GB a pop), but suddenly your sandbox is also able to run iOS simulators and tap through your application within a tagged version of macOS.

If that is still not enough, products for exactly this exist. Fly.io’s Sprites offer hardware-isolated, persistent Linux VMs with Claude Code preinstalled, signed in to the existing subscription on first run, ports forwarded to localhost automatically. Pretty much all requirements checked, as a service.

But ultimately, the end goal for me personally is to run everything locally. Both in the sense of being able to work on an airplane, and to run AI models on my machine.

Code in, patches out#

There is a missing scenario in the previous section, sitting between the two extremes. Let’s say we are developing a frontend for a secret confidential library. It would be nice to use state of the art models for the frontend without exposing anything secret, but if the library is committed to git history, handling is not frictionless.

The solution is the seed command from a repository root dir. It copies the tracked files only from host into the sandbox and commits them as a fresh repository, in one history-free baseline commit.

$ sandbox new
ready: sandbox shell still-violet  (mode: Claude, backend: orb)

$ sandbox seed still-violet --exclude=libsecret/ --mock=path/to/build/libsecret
seeded: /Users/marcel/Sandboxes/Claude/still-violet/repo

$ sandbox shell still-violet
marcel@still-violet:/workspace$ cd repo && git log
commit d34941dd03f3c80feafed5ed183f52f18746656a (HEAD -> main)
Author: Sandbox Agent <[email protected]>
Date:   Tue Aug 4 13:09:15 2026 +0200

    baseline

In order to close the loop on the requirements, that the agent can run and verify their changes, it’s not enough to just exclude the secret library at libsecret/ and collapse the git history. Above, a prepared mock library took its place instead. This could be itself a rabbit hole, but for projects where the header files were not confidential (just the implementation) this works well.

And finally, there is sandbox export still-violet, which generates a dated git patch (within the sandbox) from the sandbox changes and places it in the real repository for review. Yes, human reviewed and committed.

Branching#

Instead of cloning the base image, it’s also possible to do the same with any existing sandbox. This will bring along everything in the container, including a forked Claude Session, databases, installed dependencies, etc. And all that within seconds, which feels like git branching.

The obvious worry is the Claude Code session, how will a forked sandbox mid-conversation react? It turns out that sessions are file-based on the machine and cloning duplicates them. I was able to diverge independently in one sandbox and continue where left off in the original machine. I’m not sure how stable or true this is in the future, but it’s something that I always felt was missing in the web versions of LLMs.

$ sandbox branch soft-lake soft-lake-alt
branched: soft-lake -> soft-lake-alt  (mode: Claude, backend: orb)

# Experiment...

$ sandbox rm soft-lake-alt

The original sandbox now acts more like a snapshot that can be returned to, without any clean-up or reversal efforts, providing “cheap” divergence in the form of fast clone/discard.

Conclusion#

Having a git-like interface for quickly creating and discarding sandboxes has proven to fit my workflows very naturally and prior concerns like confidential libraries are no obstacle anymore.

This approach is very extendable and maybe even a whole product could be built from it. But there is a certain elegance in just composing trusted components. Maybe some readers will find this script and a personalised setup.sh useful for their own way of working.