One command, one screen, then it runs
paddock run starts a sandboxed session in the terminal you
are already in. No daemon, no tab to open. It opens on the profile you launched last:
L, then enter.
The confirm screen is not optional and does not shrink for a repeat launch. The thing granting the permissions says out loud what it granted: groups expanded, paths as they will be.
$ paddock run
paddock local-model in ~/dev/agentlab
1 Open New sandbox
2 Profile local-model
> 3 Backend msb (a microVM, full isolation)
4 Agent Local inference (aider --no-auto-commits)
5 Tools none
6 Network only Local inference's own API (1 domain)
7 Files ~/dev/agentlab
8 Skills none for this agent
9 Advanced name, save as profile, keep running, MCP
What runs the sandbox. srt wraps the process in the OS policy and starts at
once. msb boots a microVM, which is slower to start and shares less with this
machine.
[ Launch ] [ Cancel ]
enter edit ^v move 1-9 jump L launch s save esc cancel ? keys
Launch this sandbox?
session local-model-4a7f
backend msb (a microVM, full isolation)
agent Local inference (aider --no-auto-commits)
profile local-model, unchanged
can write everything in the guest, which goes when it does, and
~/dev/agentlab, mounted at /work
can read the guest's own filesystem. Your disk is not in there at all, so
none of it has to be denied
can reach 1 domain: localhost:11434
can run whatever the python:3.12-slim image ships, plus local itself
can see its own Local inference login. No other agent's keys. No skills.
> [ Launch ] [ ← Back to the form ] [ Cancel ]
enter choose <> move ^v scroll s save esc back (keeps your answers)
paddock: pulling the python:3.12-slim image
paddock: installing local in the guest
paddock: the first start takes about 40 seconds
paddock: session local-model-4a7f
tui.py and
screen.py. Standalone paddock run and the port-scoped local
rule are on develop at v0.2.0, not yet on main.
Full reference.In herdr the same chooser opens
on prefix+s and adds sandboxed tabs, named sessions and re-attach. Outside
it, one terminal is one session.
Every grant is decided before the first token
No runtime prompts to argue past. Writes and domains are settled in the kernel sandbox, and unticked skills and MCP servers are not in the session's config directory to find.
- can run
-
Only the binaries you tick, plus what the agent cannot start without.
Soft. An absolute path still reaches any host binary. On
msbthere is none to reach. - can reach
-
A domain allowlist, by group or by name. Everything else refused by the OS.
Hard, one hole. On
msbDNS is all or nothing: every name resolves, then the connection is refused. Names leak. - can write
-
Denied by default. A scratch directory, or the one host directory you named.
No opt-out. No allow-everything row. A sandbox with no filesystem fence is a local tab, one field up.
- can read
-
Your disk, minus the credential directories:
~/.ssh,~/.aws,~/.gnupg,~/.config/gh. On a microVM none of it is in there. - can see
-
The agent's own login, nothing else. What it writes back are copies, so no agent gets another's keys, your SSH keys or your cloud credentials.
Two backends enforce it, and they differ in kind, not spelling. The chooser refuses an answer a backend cannot express.
srt policy sandbox
- Start
- Instant. Milliseconds, which is what a keybinding needs.
- Boundary
- Seatbelt on macOS, bubblewrap on Linux, through Anthropic's sandbox-runtime.
- Shares
- This machine's kernel and filesystem, minus what the policy refuses.
msb microVM
- Start
- 175ms from create to a usable VM. A first agent session is about 40s: the agent installs in the guest.
- Boundary
- A libkrun microVM with its own kernel and filesystem. No server, no daemon, no privileged step.
- Shares
- Only the directory you mounted.
The agent in the VM, the model on your GPU, one port between them
On msb, naming a local port writes one network rule: reach
this machine, on that port. Not another port, not the internet, not even DNS.
Host
Your GPU, your server- ollama, LM Studio,
- llama.cpp, vLLM
- 127.0.0.1:11434
- never published
Guest
The agent, in a microVM- a kernel of its own
- /work, and nothing else
- OPENAI_BASE_URL set
- gone when the session ends
Every runtime is an HTTP server on a port, so all of them are the same shape. Name it once and the guest boots knowing where it is.
# the agent file that opens the port, once "api_domains": ["localhost:11434"] # what the guest boots with, in every tab OPENAI_BASE_URL=http://host.microsandbox.internal:11434/v1 OLLAMA_HOST=http://host.microsandbox.internal:11434
Leave your server on loopback. The gateway connects
onward from the host, so 127.0.0.1 is where the request arrives. Serving to
the network would hand the model to the whole Wi-Fi, and paddock does not need it.
Another port on the same host, from inside the guest:
wget: can't connect to remote host (172.16.2.213): Connection refused msb 0.6.13, with a 27B model answering from inside the guest, /Users absent and example.com not resolving.
On srt the grant is not scoped: Seatbelt's
loopback rule takes no port, so it opens every service on this machine. The confirm
screen says so. For the narrow version, use msb.
What it is not, yet
A tool that hands out permissions has to be honest about its own.
- Three enforcement layers, two of them hard. The kernel sandbox and the synthesized config directory sit outside the agent. The generated agent config is the agent enforcing a rule on itself: friction, not a boundary.
- The tool list is a soft allowlist. It shapes what the agent finds. It does not stop an absolute path. Hard per-binary blocking is on the roadmap.
- Collection is lazy. Nothing watches for a closed tab, so a session is collected at the next paddock command. Until then its microVM is up and holding memory.
paddock gcforces it.

paddock