Let a coding agent run wild on your repo, without trusting it.
drydock runs Claude Code, OpenAI Codex, or any OpenAI-compatible model full-throttle on a copy of your repo, sealed inside a throwaway VM on your own Mac. The agent never sees your API key and has no open internet. The only thing that comes back is a git diff, and nothing touches your real code until you approve it.
Bring an API key, or run on the Claude Pro/Max or ChatGPT plan you already pay for: no key in the VM, no metered spend.
brew install sricola/drydock/drydock
beta · v0.6.7 macOS 26+ on Apple silicon · no third-party audit yet. Every containment claim is a runnable test, so run the attacks yourself.
Core security guarantees
Your key never enters the VM
A credential gateway on the host swaps in a short-lived, budget-scoped token. The agent can spend its allowance, but it can never read, log, or leak the key.
No open internet
Egress is deny-by-default through a host-side proxy. The agent reaches the model API and the package registries you allow, and nothing else. Widening is per-task and human-approved.
Only a diff comes back
The VM is destroyed after every task; nothing persists. The work survives as a git diff that lands only after you read and approve it.
Don't take the threat model's word for it.
Every containment claim is a real go test red-team case that runs the actual attack (key exfiltration, hostile egress, cross-task persistence) and asserts it fails. Run them on your own machine. No API key, no spend, about five minutes.
# the live containment attacks: key exfil, egress, ephemerality drydock redteam # …or watch all seven, including live VM isolation make demo VM=1
go test red-team case.And verify what you're running
- Reproducible binaries: rebuild a release and compare checksums byte-for-byte.
- Signed + attested releases: Sigstore cosign signatures and SLSA build provenance on every tag.
- SBOM per release: a CycloneDX inventory of everything inside.
- Scanned daily: govulncheck gates every commit; the sandbox image is CVE-scanned in CI, with exceptions public and expiring.
Three steps. The agent never gets the keys to your machine.
-
Point it at a repo
Give drydock a repo URL and a task. It clones a disposable copy and boots a fresh VM around it.
-
The agent runs sealed
No key, no host access, no open internet. It works the copy at full tilt: no permission prompts, no babysitting.
-
You approve the diff
Review in the terminal or the local web board (drydock ui), then approve or deny. Approved diffs push to a branch; denied ones vanish with the VM.
# one task, from prompt to the approval gate drydock submit --repo git@github.com:you/repo \ --instruction "Add tests for the auth module." task ab12cd34 accepted preparing · cloning repo running · claude working (sealed VM, no key, no open net) ⏸ awaiting approval · 1.2 KB diff (4 files) review: drydock review ab12cd34 approve: drydock approve ab12cd34 ✓ pushed agent/ab12cd34 · 4 files +120/-8 · 2m18s · $0.11
Two commands to a sealed first task.
# install, then one command sets up the runtime + proxy brew install sricola/drydock/drydock drydock setup # credential: a vendor API key… export ANTHROPIC_API_KEY=sk-ant-… # …or no key at all, reuse a plan you already pay for: # drydock auth claude # Claude Pro/Max # drydock auth codex # ChatGPT drydock start # then hand it a real task (blocks until you approve the diff): drydock submit --repo git@github.com:you/repo --instruction "…"
Supported agents and credentials
Bring an API key, or run on your existing Claude Pro/Max or ChatGPT subscription with no key at all. Either way the credential stays on your Mac; the VM only ever sees a per-task token. Authentication → Bring your own model →
A container shares your kernel. This doesn't.
Docker is a fine tool; it just answers a different question. On macOS, containers share one Linux VM and one kernel, and a container does nothing about the parts that actually leak: your API key in the env, unrestricted egress, and an agent pushing straight to origin.
drydock gives every task its own hardware-isolated VM via Apple's container runtime, and puts the missing controls on the seam: a credential gateway (the key never enters), a deny-by-default egress proxy, and a human approval gate in front of every push. The isolation is the floor, not the feature.
What's contained, and the residual risk.
| Attack | What drydock does | Residual risk |
|---|---|---|
| Exfiltrate your API key | The real key never enters the VM. The agent gets only a short-lived, budget-scoped token via the gateway. contained | A leaked token is rate- and budget-limited, and dies with the task. scoped |
| Call home / exfiltrate code | Egress is deny-by-default; the agent reaches only your allowlist, through the proxy. contained | An allow-listed host is still reachable; widening is human-approved per task. your call |
| Persist / tamper with your machine | The VM is a throwaway, destroyed after each task; your real repo and credentials are never mounted into it; the agent works a disposable copy. contained | None on the host; any persistence dies with the VM. in-VM only |
| Sneak a backdoor into the diff | Nothing reaches origin until you read the diff and approve it. gated | drydock makes a malicious diff reviewable, not impossible: approve a subtle one and it lands. on you |
The full threat model is the contract: it enumerates every attack and what drydock does and doesn't defend. A containment that overclaims fails quietly, so it also names the edges, prompt injection is contained, not prevented; a subtle backdoor you approve still lands; a compromised host is out of scope; and it is pre-1.0 with no third-party security audit. Read it before you trust it.