claudebox/README.md
Christopher Mühl aff389b9d4
feat: env files and fix NixOS SSL cert passthrough
- ~/.claudebox/env and <project>/.claudebox.env loaded at launch
- NIX_SSL_CERT_FILE passed from host instead of hardcoded path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 18:11:56 +02:00

3.3 KiB

claudebox

Run Claude Code inside a bubblewrap sandbox with an allowlisted environment, explicit filesystem mounts, and a minimal PATH.

SSH keys, GPG/age secrets, cloud tokens, and Tailscale state stay completely invisible to the AI agent. If a secret is accessible inside the sandbox, it's a bug.

Quick start

nix run git+https://git.toph.so/toph/claudebox

Or add to your flake:

{
  inputs.claudebox.url = "git+https://git.toph.so/toph/claudebox";
}

Then add inputs.claudebox.packages.${system}.default to your environment.systemPackages or home-manager packages.

What it does

  • Starts Claude Code inside a bwrap namespace with --clearenv
  • Only allowlisted env vars enter the sandbox (HOME, PATH, TERM, EDITOR, LANG, ANTHROPIC_API_KEY if set)
  • Mounts CWD read-write, Nix store read-only, everything else is tmpfs
  • Provides nix shell and comma (, <tool>) so Claude can install tools on demand
  • Injects a SANDBOX.md so Claude knows it's sandboxed and how to get tools
  • Pre-configures git identity and safe.directory from host

Flags

Flag Description
--yes, -y Skip the env audit and launch immediately
--dry-run Print the bwrap command without executing
--check Verify prerequisites and exit
--shell Drop into a bash shell instead of Claude Code
--gc Remove stale per-project instance dirs and exit
-- Pass remaining args to Claude Code

Env vars

Env files (preferred) — define vars without polluting your shell:

~/.claudebox/env — global, loaded on every launch:

ANTHROPIC_API_KEY=sk-ant-...
MY_GLOBAL_VAR=value

<project>/.claudebox.env — per-project, loaded when present:

DATABASE_URL=postgres://localhost/myapp
SOME_PROJECT_VAR=value

Add .claudebox.env to your .gitignore if it contains secrets.

Pass-through — inject host vars already set in your shell:

CLAUDEBOX_EXTRA_ENV=MY_VAR,OTHER_VAR claudebox

All injected vars appear in the [+] section of the env audit.

How it works

~/.claudebox/          # persistent config dir (host)
├── SANDBOX.md         # managed by claudebox, overwritten each launch
├── history.jsonl      # conversation history
├── .credentials.json  # Claude Code credentials (if present)
└── projects/
    └── <16-char-hex>/ # per-project instance dir (keyed by canonical git root)
        └── project-root  # records the canonical path for this instance

Inside the sandbox:
  ~/.claude            →  bind-mounted from host (plugins, skills, hooks, MCP all visible)
  ~/.claude/projects   →  bind-mounted from ~/.claudebox/projects/<hash>/ (per-project isolation)
  ~/.claude/history.jsonl → bind-mounted from ~/.claudebox/history.jsonl
  ~/.claude/SANDBOX.md →  bind-mounted from ~/.claudebox/SANDBOX.md

Each project gets an isolated ~/.claude/projects/ directory inside the sandbox, so conversation history and project state are separated per repo. Git worktrees share the same instance dir as their main worktree.

Requirements

  • NixOS or Nix with flakes enabled
  • User namespaces (enabled by default on NixOS)

License

MIT