Use this file to answer three questions quickly:
- Which boundary should I choose?
- Why does Docker change the answer?
- Which deeper doc should I read next?
Autonomous agent modes bypass most of the friction that normally slows down a
mistake. Claude Code --dangerously-skip-permissions, Qwen --yolo, and
similar harness modes can execute shell commands and make network calls with the
privileges of the environment they are running in. A prompt injection, malicious
repository file, compromised MCP server, or bad dependency can then act as that
environment.
The point of sandboxing is not to make the agent "behave." It is to limit the blast radius when it does not.
| Situation | Recommended tier | Why |
|---|---|---|
| Trusted repo, interactive use, low stakes | Tier 0 or Tier 1 | Lowest friction; enough when you are watching closely |
| Need strong isolation without a VM and the repo does not need Docker | Tier 2 | Separate macOS user gives the biggest jump in blast-radius reduction |
| Repo needs Docker and can use a private daemon or microVM | Tier 3 | Docker changes the boundary question; give the agent its own daemon |
| Repo depends on a shared host Docker daemon | Tier 4, or Tier 2 code-only | Shared-daemon access is outside Hazmat containment |
| Unfamiliar repo, heavy autonomy, or sensitive environment | Tier 4 | Full VM plus rollback is the strongest practical answer |
Hazmat has bounded Linux support now, but Linux native agent launch is not the supported default yet.
- Linux native is plan-only: platform probes, capability-gap reporting, a
linux-nativelaunch-spec compiler, Linux package tests, and Linux CI lanes exist. The guarded native launch helper, setup, rollback, and release artifacts are not implemented yet. - Apple Container is experimental exec-only: on macOS 26 Apple silicon,
hazmat exec --backend=apple-container --image ... -- <command>can run a Linux command in a short-lived VM whenHAZMAT_EXPERIMENTAL_APPLE_CONTAINER=1is set. It is useful for Linux workloads, but host file IO happens as the invoking macOS user, so it is not equivalent to Tier 2 dedicated-user native containment. - macOS native remains the production path: the tier table below describes the supported day-to-day containment boundary for AI coding agents today.
Think about the design in layers. Each tier covers some layers better than others.
This is the immediate surface: repo files, CLAUDE.md, hidden prompts in documents, hooks, local tooling, and shell execution. Tier 0 and Tier 1 mainly operate here.
This is everything reachable from the user account running the agent: ~/.ssh, ~/.aws, ~/.claude, shell config, Keychain-adjacent paths, and browser/session material. Tier 2 is the first tier that changes this meaningfully by switching to a different macOS user.
This is outbound exfiltration, localhost service abuse, and what the agent can reach on the LAN or internet. pf, proxying, deny-by-default networking, and isolated networks all matter here.
This includes Docker daemons, host services, shared sockets, hypervisors, and anything else that lets the agent ask a more privileged component to act on its behalf. This is why Docker is not just "another binary." If a project needs Docker, the design should usually move from Tier 2 to either Tier 3 (private daemon) or Tier 4 (shared-daemon workflow).
This is what happens after compromise: modified shell rc files, LaunchAgents, poisoned caches, resource exhaustion, and whether you have a clean rollback path. Tier 4 is strongest here because snapshots make recovery predictable.
For the attack-by-attack view, read threat-matrix.md. For concrete incidents that motivated these layers, read incidents-and-cves.md.
| Tier | Main boundary | Strengths | Main gaps | Best fit |
|---|---|---|---|---|
| 0 | Harness built-in controls | Minimal setup, native speed | Not a strong security boundary | Trusted repos, supervised work |
| 1 | Same-user process wrapper | Better filesystem and network policy control | Still same macOS user; limited against broader host exposure | Trusted repos with a bit more rigor |
| 2 | Dedicated macOS user + pf + host-side wrappers |
Strong no-VM blast-radius reduction; separate home and configs | Docker is intentionally blocked; container traffic is a different surface | Daily development on non-Docker projects |
| 3 | Docker Sandboxes / private daemon / devcontainer | Best balance when Docker is required and the repo fits a private daemon | Shared-daemon projects are out of scope; continuity with Tier 2 is still rough | Self-contained Docker repos and medium-to-high risk work |
| 4 | Full VM | Strongest isolation and recovery story | Highest operational overhead | Untrusted repos, long autonomy, sensitive environments |
Docker is a separate design branch because a shared daemon is effectively a privileged helper. If the agent can reach a Docker daemon that is not exclusively its own, it can often create containers with bind mounts, privileged flags, or other settings that bypass the intended boundary.
That produces three practical rules:
- Tier 2 native containment is the default for code editing, with Docker disabled.
- If the session needs Docker and the repo can live inside a private daemon, opt into Tier 3 with
--docker=sandbox,--docker=auto, or project config. - If the project depends on the host Docker daemon, do not punch a hole through Tier 2. Use Tier 4, or accept the default code-only Tier 2 session.
Read tier3-docker-sandboxes.md for the private-daemon path and shared-daemon-projects.md for the unsupported shared-daemon case.
flowchart TD
Start([Which tier?]) --> Q1{Trusted repo +<br/>supervised use?}
Q1 -- yes --> T01["Tier 0 or 1<br/><em>process-level controls</em>"]
Q1 -- no --> Q2{Needs Docker<br/>or Compose?}
Q2 -- yes --> Q2A{"Needs the host<br/>Docker daemon?"}
Q2A -- no --> T3["Tier 3<br/><em>dedicated daemon / microVM</em>"]
Q2A -- yes --> T4A["Tier 4 or Tier 2 code-only<br/><em>shared-daemon project</em>"]
Q2 -- no --> Q3{Unattended, sensitive<br/>data, or hostile repo?}
Q3 -- yes --> T4["Tier 4<br/><em>full VM + snapshot rollback</em>"]
Q3 -- no --> T2["Tier 2<br/><em>dedicated macOS user + pf</em>"]
style T01 fill:#dfd,stroke:#3a3,color:#000
style T2 fill:#ddf,stroke:#33a,color:#000
style T3 fill:#ffd,stroke:#a80,color:#000
style T4 fill:#fee,stroke:#c33,color:#000
- Is the repo trusted and are you supervising closely? If yes, Tier 0 or Tier 1 may be enough.
- Does the repo need Docker, Docker Compose, or a devcontainer workflow? If no, keep evaluating Tier 2.
- If yes, can the repo run against a private daemon or microVM? If yes, go to Tier 3. If it needs the host daemon, use Tier 4 or a code-only Tier 2 session.
- Do you want the strongest non-VM boundary for normal development? Use Tier 2.
- Are you running unattended, handling sensitive data, or working with hostile repos? Use Tier 4.
The key UX improvement in Hazmat's dedicated-user setup is that you stay in your
normal shell while the agent process runs as the isolated agent user:
hazmat claude,hazmat codex,hazmat opencode,hazmat antigravity,hazmat hermes, andhazmat qwenlaunch supported harnesses in containmenthazmat shellopens an interactive contained shellhazmat exec -- <command>runs one-off tools likemake,npx,uv, anduvx
That preserves the boundary without forcing the user to live inside sudo -u agent -i.
Session integrations provide per-stack session ergonomics
(read-only toolchain paths, snapshot excludes, safe env passthrough) without
weakening Tier 2's containment. Repos can still recommend integrations via
.hazmat/integrations.yaml; hazmat prompts once for approval.
Claude Code remains the clearest example of the application-level permission model Hazmat is designed to sit outside. It has five permission modes, from most restrictive to most permissive:
| Mode | Behavior |
|---|---|
| Plan Mode | Read-only. Claude can analyze but cannot modify anything. |
| Normal Mode | Default. Prompts for confirmation before every sensitive operation. |
| Auto-accept Edits | Auto-approves file read/write. Shell commands still require validation. |
| Don't Ask Mode | Auto-denies all tool usage unless pre-approved via /permissions. |
Bypass Mode (--dangerously-skip-permissions) |
Skips all permission checks. Everything runs without prompting. |
- Read threat-matrix.md if you want the risk-by-risk comparison.
- Read architecture.md if you want the module graph, invariants, and data/user-flow diagrams.
- Read attack-surface-deep-dive.md if you want the escape and exfiltration details.
- Read incidents-and-cves.md if you want the real incidents and CVEs that justify the controls.
- Read usage.md once you want command-by-command setup and daily workflow guidance.
- Read tier3-docker-sandboxes.md once you know a private-daemon Docker boundary is the right fit.