claudebox/.planning/PROJECT.md
Christopher Mühl 6465da8583 feat(04-01): add credential file mount for OAuth passthrough
- Add CREDS_FILE/CREDS_MOUNT detection after mkdir ~/.claudebox
- Conditional --bind in exec bwrap via BWRAP_ARGS array
- Mirror conditional bind in --dry-run display block
- Read-write mount (not ro-bind) for OAuth token refresh
- Silent skip when credentials file absent (no error/warning)
- Refactor exec bwrap to BWRAP_ARGS array for conditional mount support
2026-04-10 09:20:18 +00:00

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

Core Value

Secrets never enter the Claude Code environment. If a secret is accessible inside the sandbox, it's a bug.

Requirements

Validated

  • Default prompt/instructions injected so Claude knows how to use nix/comma to get dev tools — Validated in Phase 3: Sandbox-Aware Prompting

Active

  • Wrapper script that execs claude --dangerously-skip-permissions inside a bwrap sandbox
  • Environment allowlist: start with empty env, explicitly pass only known-safe vars (HOME, PATH, TERM, EDITOR, LANG, etc.)
  • Pre-launch env audit: before running, list all env vars being passed in so the user can review for secrets. Proceed on confirmation, abort on rejection
  • --yes / -y flag to skip the env audit and launch immediately
  • Filesystem isolation: only CWD mounted read-write, plus ~/.claudebox mapped to ~/.claude inside the sandbox
  • Secret paths hidden: ~/.ssh, ~/.gnupg, ~/.config/gcloud, ~/.aws, Tailscale state, age keys — none of these visible inside the sandbox
  • Minimal PATH: Nix store paths only — coreutils, git, curl, jq, ripgrep, fd, nix, comma
  • Claude can self-install tools via nix shell or , <tool> (comma) inside the sandbox
  • Default prompt/instructions injected so Claude knows how to use nix/comma to get dev tools — Validated in Phase 3
  • Works on endurance (NixOS desktop)

Out of Scope

  • Network isolation — trusting Claude Code's built-in proxy for domain allowlisting
  • NixOS module form — this is a wrapper script derivation, not a services/programs module
  • Configurable per-project profiles — v1 is one tool set, profiles come later
  • Shareability — personal tool first, not designed for others yet

Context

  • Target machine: endurance (NixOS desktop)
  • Claude Code already has bubblewrap sandboxing (--sandbox) but it doesn't control env vars or secret file visibility — that's claudebox's job
  • bwrap is in nixpkgs, so the derivation uses writeShellApplication wrapping a bwrap invocation
  • ~/.claudebox/ is the persistent config directory that gets bind-mounted as ~/.claude inside the sandbox, keeping real ~/.claude outside
  • comma (,) is a tool that runs nix shell nixpkgs#<pkg> -c <pkg> — lets Claude pull in any tool on demand without pre-declaring it
  • The Nix store needs to be mounted read-only inside the sandbox for nix/comma to work

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 — Pending
Env allowlist over denylist Denylist misses unknown vars; allowlist is secure by default — Pending
comma for tool access Claude can pull any tool on demand without pre-declaring PATH entries — Pending
--dangerously-skip-permissions always The bwrap sandbox IS the permission layer — Claude's prompts are redundant — Pending
Pre-launch env audit User reviews exactly what enters the sandbox, catches leaks before they happen — Pending

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-09 after Phase 3 completion