claudebox/CLAUDE.md

135 lines
6.9 KiB
Markdown

<!-- GSD:project-start source:PROJECT.md -->
## Project
**claudebox**
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.
### 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
<!-- GSD:project-end -->
<!-- GSD:stack-start source:research/STACK.md -->
## Technology Stack
## Recommended Stack
### Core: Nix Derivation via `writeShellApplication`
| Technology | Version | Purpose | Why | Confidence |
|------------|---------|---------|-----|------------|
| `writeShellApplication` | nixpkgs stable | Produce the `claudebox` wrapper script | Generates a shellcheck-validated bash script in the Nix store with runtime PATH wired to declared `runtimeInputs`. Superior to `writeShellScriptBin` because it runs shellcheck at build time and sets `set -euo pipefail` automatically. | HIGH |
| `bubblewrap` (bwrap) | 0.9.x+ | Sandbox runtime | Unprivileged user-namespace sandbox. In nixpkgs as `bubblewrap`. No setuid needed on NixOS (user namespaces enabled by default). | HIGH |
| `claude-code` | CLI | The wrapped tool | Provided by Anthropic's npm/standalone installer. Assumed pre-installed or passed as input. | HIGH |
### Runtime Dependencies (runtimeInputs)
| Package | Purpose | Why This One | Confidence |
|---------|---------|--------------|------------|
| `bubblewrap` | Sandbox | The whole point | HIGH |
| `coreutils` | Basic shell utils | `env`, `cat`, `echo`, `mkdir`, etc. | HIGH |
| `git` | Version control | Claude Code requires git for repo operations | HIGH |
| `curl` | HTTP requests | Claude Code's MCP and tool use | HIGH |
| `jq` | JSON processing | Env audit display, config manipulation | HIGH |
| `ripgrep` | Search | Claude Code's preferred grep | HIGH |
| `fd` | File finding | Claude Code's preferred find | HIGH |
| `nix` | Package manager | Required for `nix shell` inside sandbox | HIGH |
| `comma` | On-demand packages | Runs `nix shell nixpkgs#<pkg> -c <cmd>` via `, <cmd>` syntax | HIGH |
| `nix-index` | Package database | Required by comma to resolve command -> package mapping | HIGH |
| `bash` | Shell | bwrap needs a shell to exec into | HIGH |
| `nodejs` | Runtime | Claude Code is a Node.js application | HIGH |
### NOT in runtimeInputs (Important)
| Package | Why Excluded |
|---------|-------------|
| `gnupg` | Secret material -- explicitly hidden |
| `openssh` | Secret material -- explicitly hidden |
| `age` / `agenix` | Secret material -- explicitly hidden |
| `tailscale` | Infrastructure access -- explicitly hidden |
## Key Nix Functions
### `writeShellApplication` -- Use This
### Why NOT These Alternatives
| Alternative | Why Not |
|-------------|---------|
| `writeShellScriptBin` | No shellcheck, no automatic `set -euo pipefail`, no `runtimeInputs` wiring. You'd have to manually construct PATH. |
| `makeWrapper` / `wrapProgram` | Designed for wrapping existing binaries with env vars/flags. Overkill and wrong abstraction -- we're writing a new script, not patching an existing binary. |
| `symlinkJoin` + `makeWrapper` | Pattern for combining multiple derivations. Not needed -- we have one script. |
| `stdenv.mkDerivation` | Too heavy. `writeShellApplication` is a specialized shortcut for exactly this use case. |
| `runCommand` / `writeScript` | Lower-level, no shellcheck, no runtimeInputs. |
## Bubblewrap Flags
### Namespace Isolation
### Filesystem Mounts
### Mount Ordering Matters
### Environment Handling
### Process Execution
## Comma and nix-index
### How Comma Works
### Packaging in nixpkgs
- `pkgs.comma` -- the comma binary itself
- `pkgs.nix-index` -- the indexer that builds/queries the database
- Database: comma needs a pre-built index. Two options:
### For claudebox
- Mount `~/.cache/nix-index` read-only into the sandbox (if using nix-index-database on the host)
- Or use the `nix-index-database` flake's `comma-with-db` package which bundles the database
## Flake Structure
### Why `builtins.readFile` for the Script Body
- Shell syntax highlighting in editors
- Shellcheck can run independently
- Easier to iterate on the script without touching Nix expressions
- `writeShellApplication` still runs shellcheck on it at build time
## PATH Construction Inside Sandbox
## Nix Store Access Inside Sandbox
## Testing Strategy
## Sources
- Training data knowledge of nixpkgs `writeShellApplication` (stable API since 2022)
- Training data knowledge of bubblewrap (stable API, project is mature)
- Training data knowledge of comma/nix-index-database (nix-community project)
- **All versions should be verified against current nixpkgs before implementation**
## Verification Checklist (for implementation phase)
- [ ] Confirm `bubblewrap` version in current nixpkgs channel
- [ ] Confirm `comma` and `nix-index-database` flake are current and compatible
- [ ] Test Nix daemon socket access through bwrap bind mount
- [ ] Test mount ordering with CWD under $HOME
- [ ] Confirm `--clearenv` + `--setenv` pattern works with Claude Code (it may need vars we haven't listed)
- [ ] Check if Claude Code needs `~/.local` or `~/.config` beyond `~/.claude`
<!-- GSD:stack-end -->
<!-- GSD:conventions-start source:CONVENTIONS.md -->
## Conventions
Conventions not yet established. Will populate as patterns emerge during development.
<!-- GSD:conventions-end -->
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
## Architecture
Architecture not yet mapped. Follow existing patterns found in the codebase.
<!-- GSD:architecture-end -->
<!-- GSD:skills-start source:skills/ -->
## Project Skills
No project skills found. Add skills to any of: `.claude/skills/`, `.agents/skills/`, `.cursor/skills/`, or `.github/skills/` with a `SKILL.md` index file.
<!-- GSD:skills-end -->
<!-- GSD:workflow-start source:GSD defaults -->
## GSD Workflow Enforcement
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
Use these entry points:
- `/gsd-quick` for small fixes, doc updates, and ad-hoc tasks
- `/gsd-debug` for investigation and bug fixing
- `/gsd-execute-phase` for planned phase work
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
<!-- GSD:workflow-end -->
<!-- GSD:profile-start -->
## Developer Profile
> Profile not yet configured. Run `/gsd-profile-user` to generate your developer profile.
> This section is managed by `generate-claude-profile` -- do not edit manually.
<!-- GSD:profile-end -->