SkillAgentSearch skills...

Hazmat

macOS containment for AI agents — user isolation, kernel sandbox, pf firewall, DNS blocklist, backup/rollback. TLA+ verified.

Install / Use

/learn @dredozubov/Hazmat

README

<p align="center"> <a href="#"><img src="assets/hazmat-final.png" alt="Hazmat" width="400"></a> </p> <h1 align="center">Hazmat</h1> <p align="center"> <strong>Full autonomy. Controlled environment.</strong><br> OS-level containment for AI coding agents on macOS </p>

AI coding agents are most useful when you let them work autonomously. But full autonomy means the agent runs with your full privileges, your credentials, your files.

Hazmat makes that safe.

hazmat claude                     # Claude Code with full containment
hazmat opencode                   # OpenCode with full containment
hazmat exec ./my-agent-loop.sh    # any agent, any script

One command. The agent gets its own macOS user, a kernel-enforced sandbox, a firewall, and automatic pre-session backups. You get full productivity without the risk.

What You See

Every session starts with a contract — a plain-language summary of what the agent can and can't do:

hazmat: session
  Mode:                 Native containment
  Why this mode:        using native containment because no Docker requirement was detected
  Project (read-write): /Users/dr/workspace/my-app
  Integrations:         go
  Auto read-only:       /Users/dr/go/pkg/mod
  Read-only extensions: none
  Read-write extensions: none
  Service access:       none
  Pre-session snapshot: on
  Snapshot excludes:    vendor/

If the project looks compatible with a private Docker daemon, Hazmat switches modes automatically:

hazmat: session
  Mode:                 Docker Sandbox
  Why this mode:        using Docker Sandbox because this project appears compatible with a private Docker daemon (Dockerfile)
  Project (read-write): /Users/dr/workspace/api-service
  Integrations:         node
  Auto read-only:       none
  Read-only extensions: none
  Read-write extensions: none
  ...

Preview any session before running it with hazmat explain.

The Problem

--dangerously-skip-permissions is where the real productivity is. Permission prompts break flow, interrupt agent loops, and make multi-step tasks impractical. Every serious Claude Code user ends up here eventually.

But the built-in protections aren't enough:

  • Agents actively reason about escaping. Ona's research showed Claude Code bypassing its own denylist via /proc/self/root path traversal, then attempting to disable bubblewrap when that was caught.
  • 16 Claude Code CVEs and counting. CVE-2025-59536: RCE through project config files. CVE-2026-25725: sandbox escape via settings.json injection. CVE-2026-21852: API key exfiltration before the trust prompt appeared.
  • Supply chain attacks execute instantly. The axios npm compromise (2026) delivered a RAT through a postinstall hook in 2 seconds — before npm install even finished. The s1ngularity attack weaponized Claude Code itself to steal credentials.

No single layer is enough. A seatbelt profile can block file reads — but not HTTPS exfiltration. A firewall can block protocols — but not credential access. You need all of them working together.

What Hazmat Does

hazmat claude                     # Claude Code with full autonomy
hazmat exec ./my-agent-loop.sh    # any agent, any script
hazmat shell                      # interactive contained shell

| Layer | What it protects | |-------|-----------------| | User isolation | Dedicated agent macOS user. Your ~/.ssh, ~/.aws, Keychain — structurally inaccessible | | Kernel sandbox | Per-session seatbelt policy. Project gets read-write, everything else denied | | Credential deny | SSH keys, AWS creds, GPG keys, GitHub tokens — blocked at the kernel level, even inside agent home | | Network firewall | pf rules block SMTP, IRC, FTP, Tor, VPN, and other exfiltration protocols | | DNS blocklist | Known tunnel/paste/C2 services (ngrok, pastebin, webhook.site) resolve to localhost | | Supply chain hardening | npm ignore-scripts=true by default — blocks the entire class of postinstall attacks | | Automatic snapshots | Kopia snapshots before every session — roll back if the agent breaks something |

Docker Projects

Hazmat distinguishes between two Docker shapes:

  • Private-daemon Docker projects auto-route into Docker Sandbox mode. The agent runs inside an isolated sandbox with its own private Docker daemon.
  • Shared-daemon Docker projects do not. If the repo appears to depend on the host Docker daemon, Hazmat stops and asks you to choose an explicit code-only session (--docker=none) or move the workflow to Tier 4.

Use hazmat config docker none -C /path/to/project to persist code-only routing for a shared-daemon repo. See docs/tier3-docker-sandboxes.md and docs/shared-daemon-projects.md.

Comparison

| | Built-in sandbox | Agent Safehouse | SandVault | nono | Docker | Hazmat | |---|:---:|:---:|:---:|:---:|:---:|:---:| | Separate user account | — | — | ✓ | — | ✓ | ✓ | | Seatbelt / kernel sandbox | ✓ | ✓ | ✓ | ✓ | n/a | ✓ | | Credential path deny | — | partial | — | — | ✓ | ✓ | | Network firewall (pf) | — | — | — | — | ✓ | ✓ | | DNS blocklist | — | — | — | — | — | ✓ | | Supply chain hardening | — | — | — | — | — | ✓ | | Backup / rollback | — | — | — | ✓ | — | ✓ | | Agent-agnostic | — | ✓ | ✓ | ✓ | ✓ | ✓ | | macOS native | ✓ | ✓ | ✓ | ✓ | — | ✓ |

Quick Start

# Install via Homebrew
brew install dredozubov/tap/hazmat

# Or install from GitHub releases
curl -fsSL https://raw.githubusercontent.com/dredozubov/hazmat/master/scripts/install.sh | bash

# One-time setup (~10 min)
hazmat init --bootstrap-agent claude

# Start working
cd your-project
hazmat claude

hazmat init creates the agent user, configures containment, and sets up automatic snapshots. During interactive setup you can choose to bootstrap Claude Code, Codex, OpenCode, or skip agent installation and add one later with hazmat bootstrap .... It can also seed Claude with portable conveniences from an existing setup while keeping Hazmat in control of runtime and safety settings. Preview first with hazmat init --dry-run.

Daily Workflow

# Claude Code — full autonomy, contained
hazmat claude
hazmat claude -p "refactor the auth module"
hazmat claude -C ~/other-project

# Any command in containment
hazmat exec npm test
hazmat exec python train.py
hazmat exec ./run-agent-loop.sh

# Continue a hazmat Claude session as your normal user
claude --resume "$(hazmat export claude session)" --fork-session

# Interactive shell
hazmat shell

# See what the agent changed
hazmat diff
hazmat snapshots
hazmat restore          # undo last session

Extra Directories

The agent can only write to the project directory by default. Expose additional read-only or read-write paths explicitly:

hazmat claude -R ~/workspace/shared-lib -R ~/reference-docs
hazmat claude -W ~/.venvs/my-app
hazmat config access add -C ~/workspace/my-app --read ~/reference-docs --write ~/.venvs/my-app

-R stays read-only. -W adds another explicit writable root for that project or session. Both are enforced by the kernel sandbox — not advisory.

Session Integrations

hazmat integration list
hazmat integration show node
hazmat claude --integration node
hazmat claude --integration python-uv
hazmat config set integrations.pin "~/workspace/my-app:node,go"

Session integrations are ergonomic overlays for common stacks. They may add auto-resolved read-only toolchain paths, extend snapshot excludes, and pass through safe environment selectors like GOPATH or VIRTUAL_ENV. They do not widen write access, relax the credential deny list, or change the network policy.

If a repo mixes stacks across subdirectories, add .hazmat/integrations.yaml to the repo so users do not have to discover nested frontend or TLA+ integrations manually.

Repos can declare recommended integrations in .hazmat/integrations.yaml; Hazmat prompts once for approval, then reuses that approval until the file changes. See docs/integrations.md.

Handing a Hazmat Session Back to Host Claude

If you start a conversation inside hazmat claude and later want to continue it outside containment, export it into your normal Claude session store:

claude --resume "$(hazmat export claude session)" --fork-session
claude --resume "$(hazmat export claude session <session-id>)" --fork-session

hazmat export claude session exports the latest hazmat Claude session for the current project by default, or a specific session when you pass an ID. It copies the session bundle into your host ~/.claude/projects/... directory and prints the resume ID on stdout.

Configuration

hazmat config                                        # view everything
hazmat config edit                                   # open config in $EDITOR
hazmat config agent                                  # set API key + git identity
hazmat config import claude                          # import portable basics from an existing setup
hazmat bootstrap claude                              # install Claude Code for the agent user
hazmat bootstrap codex                               # install Codex for the agent user
hazmat config import opencode    
View on GitHub
GitHub Stars4
CategoryDevelopment
Updated8h ago
Forks0

Languages

Go

Security Score

90/100

Audited on Apr 5, 2026

No findings