5.1 KiB
claudebox
What This Is
A Nix derivation that produces a claudebox wrapper script for Claude Code. It runs Claude inside a bubblewrap sandbox with an allowlisted environment, explicit filesystem mounts, and a minimal PATH — keeping SSH keys, GPG/age secrets, cloud tokens, and Tailscale state completely invisible to the AI agent. Includes pre-launch env audit, diagnostic modes, and sandbox-aware prompting.
Core Value
Secrets never enter the Claude Code environment. If a secret is accessible inside the sandbox, it's a bug.
Requirements
Validated
- ✓ Wrapper script that execs
claude --dangerously-skip-permissionsinside a bwrap sandbox — v1.0 - ✓ Environment allowlist: start with empty env, explicitly pass only known-safe vars — v1.0
- ✓ Pre-launch env audit: list all env vars being passed in for user review — v1.0
- ✓
--yes/-yflag to skip the env audit — v1.0 - ✓ Filesystem isolation: only CWD mounted read-write, plus
~/.claudeboxmapped to~/.claude— v1.0 - ✓ Secret paths hidden:
~/.ssh,~/.gnupg,~/.config/gcloud,~/.aws, Tailscale state, age keys — v1.0 - ✓ Minimal PATH: Nix store paths only — coreutils, git, curl, jq, ripgrep, fd, nix, comma — v1.0
- ✓ Claude can self-install tools via
nix shellor, <tool>(comma) — v1.0 - ✓ Default SANDBOX.md injected so Claude knows its capabilities and constraints — v1.0
- ✓ Works on endurance (NixOS desktop) — v1.0
- ✓
--checkflag for environment diagnostics — v1.0 - ✓
--dry-runflag to print bwrap command without executing — v1.0
Active
- Host
~/.claudeauth files mounted read-only for subscription passthrough - Per-project instance directories (
~/.claudebox/instances/<hash>/.claude/) — conversation history scoped per project - Named profiles (
--profile foo/CLAUDEBOX_PROFILE=foo) defining env vars, mounts, packages, network tier - Profile storage at
~/.claudebox/profiles/ - Nix devshell/package injection per profile
- Tiered network isolation: full, internet-only (unshare-net + slirp4netns), none (offline)
Out of Scope
- NixOS module form — this is a wrapper script derivation, not a services/programs module
- Shareability — personal tool first, not designed for others yet
- Domain-level network allowlists — tiered isolation (full/internet-only/none) is sufficient for now
Context
Shipped v1.0 with 399 LOC (350 shell + 49 Nix).
Tech stack: Nix flake (writeShellApplication) + bubblewrap + comma-with-db.
Runs on NixOS (endurance) with readlink -f workaround for symlink chain resolution.
Non-NixOS support added via conditional /etc/static mount.
Constraints
- Stack: Nix derivation + shell script — no Docker, no systemd, no external dependencies beyond nixpkgs
- Sandbox: Own bwrap call — not delegating to Claude Code's
--sandboxor Nix's build sandbox - Env model: Allowlist, not denylist — start empty, add explicitly
Key Decisions
| Decision | Rationale | Outcome |
|---|---|---|
| Own bwrap over Claude's --sandbox | Full control over mounts, env, namespaces | ✓ Good |
| Env allowlist over denylist | Denylist misses unknown vars; allowlist is secure by default | ✓ Good |
| comma for tool access | Claude can pull any tool on demand without pre-declaring PATH entries | ✓ Good |
| --dangerously-skip-permissions always | The bwrap sandbox IS the permission layer — Claude's prompts are redundant | ✓ Good |
| Pre-launch env audit | User reviews exactly what enters the sandbox, catches leaks before they happen | ✓ Good |
| readlink -f for binary resolution | NixOS profile symlinks aren't visible inside bwrap; resolve to real store paths | ✓ Good |
| Claude Code via nix-claude-code flake | ryoppippi/nix-claude-code, not host PATH | ✓ Good |
| SANDBOX.md as separate file with @import | Keeps user CLAUDE.md clean, sandbox instructions always fresh | ✓ Good |
Current Milestone: v2.0 Network Isolation & Profiles
Goal: Add tiered network isolation, per-project instance isolation, named profiles, and host auth passthrough.
Target features:
- Host auth passthrough (read-only mount of auth files from
~/.claude) - Per-project instance isolation (conversation history scoped per project automatically)
- Named profiles with env vars, mounts, packages, and network tier
- Nix devshell injection per profile
- Tiered network: full, internet-only (no LAN/Tailscale), none (offline)
Evolution
This document evolves at phase transitions and milestone boundaries.
After each phase transition (via /gsd-transition):
- Requirements invalidated? → Move to Out of Scope with reason
- Requirements validated? → Move to Validated with phase reference
- New requirements emerged? → Add to Active
- Decisions to log? → Add to Key Decisions
- "What This Is" still accurate? → Update if drifted
After each milestone (via /gsd-complete-milestone):
- Full review of all sections
- Core Value check — still the right priority?
- Audit Out of Scope — reasons still valid?
- Update Context with current state
Last updated: 2026-04-10 after v2.0 milestone started