# Overview: Choosing a Hazmat Boundary on macOS

Use this file to answer three questions quickly:

1. Which boundary should I choose?
2. Why does Docker change the answer?
3. Which deeper doc should I read next?

## The Core Problem

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.

## Recommended Defaults

| 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 |

## Risk Surface Layers

Think about the design in layers. Each tier covers some layers better than others.

### 1. Project and Agent Runtime Surface

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.

### 2. User and Credential Surface

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.

### 3. Network and Localhost Surface

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.

### 4. Privileged Helper and Daemon Surface

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).

### 5. Persistence and Recovery Surface

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](threat-matrix.md). For concrete incidents that motivated these layers, read [incidents-and-cves.md](research/incidents-and-cves.md).

## Tier Summary

| 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 |

## Why Docker Changes the Decision

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](tier3-docker-sandboxes.md) for the
private-daemon path and [shared-daemon-projects.md](shared-daemon-projects.md)
for the unsupported shared-daemon case.

## Decision Flow

```mermaid
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
```

1. Is the repo trusted and are you supervising closely?
   If yes, Tier 0 or Tier 1 may be enough.
2. Does the repo need Docker, Docker Compose, or a devcontainer workflow?
   If no, keep evaluating Tier 2.
3. 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.
4. Do you want the strongest non-VM boundary for normal development?
   Use Tier 2.
5. Are you running unattended, handling sensitive data, or working with hostile repos?
   Use Tier 4.

## Dedicated-User UX Note

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 gemini`,
  `hazmat hermes`, and `hazmat qwen` launch supported harnesses in containment
- `hazmat shell` opens an interactive contained shell
- `hazmat exec -- <command>` runs one-off tools like `make`, `npx`, `uv`, and
  `uvx`

That preserves the boundary without forcing the user to live inside `sudo -u agent -i`.

[Session integrations](integrations.md) 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 Permission Modes

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. |

## What to Read Next

- Read [threat-matrix.md](threat-matrix.md) if you want the risk-by-risk comparison.
- Read [architecture.md](architecture.md) if you want the module graph,
  invariants, and data/user-flow diagrams.
- Read [attack-surface-deep-dive.md](research/attack-surface-deep-dive.md) if you want the escape and exfiltration details.
- Read [incidents-and-cves.md](research/incidents-and-cves.md) if you want the real incidents and CVEs that justify the controls.
- Read [usage.md](usage.md) once you want command-by-command setup and daily
  workflow guidance.
- Read [tier3-docker-sandboxes.md](tier3-docker-sandboxes.md) once you know a
  private-daemon Docker boundary is the right fit.
