claudebox/.planning/PROJECT.md

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-permissions inside 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 / -y flag to skip the env audit — v1.0
  • ✓ Filesystem isolation: only CWD mounted read-write, plus ~/.claudebox mapped 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 shell or , <tool> (comma) — v1.0
  • ✓ Default SANDBOX.md injected so Claude knows its capabilities and constraints — v1.0
  • ✓ Works on endurance (NixOS desktop) — v1.0
  • --check flag for environment diagnostics — v1.0
  • --dry-run flag to print bwrap command without executing — v1.0

Active

  • Host ~/.claude auth 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 --sandbox or 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):

  1. Requirements invalidated? → Move to Out of Scope with reason
  2. Requirements validated? → Move to Validated with phase reference
  3. New requirements emerged? → Add to Active
  4. Decisions to log? → Add to Key Decisions
  5. "What This Is" still accurate? → Update if drifted

After each milestone (via /gsd-complete-milestone):

  1. Full review of all sections
  2. Core Value check — still the right priority?
  3. Audit Out of Scope — reasons still valid?
  4. Update Context with current state

Last updated: 2026-04-10 after v2.0 milestone started