claudebox/.planning/phases/05-per-project-instance-isolation/05-01-SUMMARY.md

6.1 KiB

phase plan subsystem tags dependency-graph tech-stack key-files decisions metrics
05-per-project-instance-isolation 01 sandbox-mount-architecture
bwrap
mounts
isolation
per-project
instance-hash
worktree
requires provides affects
per-project-instance-isolation
direct-claude-bind
instance-hash-dirs
claudebox.sh
REQUIREMENTS.md
added patterns
sha256sum[:16] of canonical git root path for per-project instance identity
git rev-parse --git-common-dir for worktree-aware canonical root resolution
bwrap overlay mounts (last-mount-wins) on top of direct ~/.claude bind
created modified
claudebox.sh
.planning/REQUIREMENTS.md
D-01
Direct bind of ~/.claude (not ~/.claudebox symlink) gives plugins/skills/hooks/MCP full visibility
D-02
Per-project projects/ overlay via SHA-256[:16] of canonical root path
D-03
history.jsonl bind overlay from ~/.claudebox/history.jsonl
D-06
SANDBOX.md injected as file overlay; CLAUDE.md injection removed (user's real CLAUDE.md already has @SANDBOX.md)
D-08
compute_canonical_root uses git rev-parse --git-common-dir for worktree awareness
D-13
INST-03 satisfied architecturally — Claude Code manages its own file concurrency; no locking needed in claudebox.sh
/bin/sh symlink added to sandbox so hooks can exec sh (ENOENT fix)
duration completed tasks_completed files_modified
~45 minutes 2026-04-13 3 2

Phase 05 Plan 01: Mount Architecture Rewrite and Per-Project Instance Isolation Summary

Direct bind of ~/.claude into sandbox with SHA-256-keyed per-project overlay mounts, replacing the old ~/.claudebox symlink approach that hid all plugins, skills, hooks, and MCP configs from Claude Code.

What Was Built

Mount Architecture Rewrite (claudebox.sh)

Replaced the old mount approach (--bind ~/.claudebox ~/.claudebox + --symlink ~/.claudebox ~/.claude) with a new architecture:

  • --bind "$HOME/.claude" "$HOME/.claude" — direct bind, makes all Claude Code config (plugins, skills, hooks, MCP, commands, settings) visible inside the sandbox (D-01)
  • --bind "$INSTANCE_DIR" "$HOME/.claude/projects" — per-project overlay; each project gets its own isolated directory mounted over the real ~/.claude/projects/ (D-02, INST-01)
  • --bind "$HOME/.claudebox/history.jsonl" "$HOME/.claude/history.jsonl" — history overlay; conversation history stored sandbox-side (D-03)
  • --bind "$HOME/.claudebox/SANDBOX.md" "$HOME/.claude/SANDBOX.md" — SANDBOX.md injected as file overlay (D-06)
  • --bind "$CREDS_FILE" "$HOME/.claude/.credentials.json" — credential mount updated to new target path

Per-Project Instance Isolation

Added compute_canonical_root() function using git -C "$cwd" rev-parse --git-common-dir to resolve worktree-aware canonical repo root. Git worktrees return a path pointing to the main worktree's .git/, so dirname(readlink -f(git_common)) gives the main worktree root for any worktree.

Instance hash computed as: INSTANCE_HASH=$(printf '%s' "$CANONICAL_ROOT" | sha256sum | cut -c1-16)

Each project gets ~/.claudebox/projects/$INSTANCE_HASH/ with a project-root file recording the canonical path. Directory created at startup with mkdir -p.

Removed

  • Old --symlink "$HOME/.claudebox" "$HOME/.claude" (D-01 replacement)
  • Old --bind "$HOME/.claudebox" "$HOME/.claudebox" (D-01 replacement)
  • CLAUDE.md injection block (CLAUDEMD="$HOME/.claudebox/CLAUDE.md") — user's real ~/.claude/CLAUDE.md already has @SANDBOX.md (D-06)

Preserved

  • CLAUDE_JSON_FILE / CLAUDE_JSON_MOUNT conditional bind (--bind "$CLAUDE_JSON_FILE" "$HOME/.claude.json") — critical for auth token persistence

Updated

  • Dry-run block echoes new mount layout including instance dir and CLAUDE_JSON conditional
  • print_audit shows projects/ mount with instance dir path and canonical root for transparency
  • SANDBOX.md heredoc updated to remove ~/.claudebox references (no longer visible in sandbox)

Added --symlink $(which bash) /bin/sh to BWRAP_ARGS. Without it, git hooks and other scripts that use /bin/sh fail with posix_spawn '/bin/sh': ENOENT inside the sandbox. Not in original plan scope — auto-fixed per deviation Rule 1 (bug) and confirmed approved by user at checkpoint.

Requirements Registration

Added INST-01 through INST-04 to .planning/REQUIREMENTS.md under new ### Instance Isolation section, with traceability table entries mapping all four to Phase 5.

Verification Results

  • bash -n claudebox.sh passes (syntax clean)
  • compute_canonical_root present in claudebox.sh
  • INSTANCE_HASH computation present in claudebox.sh
  • New mount lines confirmed present via search
  • Old symlink/claudebox bind lines confirmed absent
  • Human checkpoint approved by user

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] Added /bin/sh symlink so hooks can exec sh

  • Found during: Task 1 (anticipated based on bwrap behavior + user confirmation at checkpoint)
  • Issue: Sandbox has no /bin/sh — git hooks and POSIX scripts that call /bin/sh fail with posix_spawn '/bin/sh': ENOENT
  • Fix: Added --symlink $(which bash) /bin/sh to BWRAP_ARGS
  • Files modified: claudebox.sh
  • Commit: 4baf576

Known Stubs

None. All mount architecture changes are fully wired. Per-project instance dirs are created and used at runtime. No placeholder data flows to any UI or output.

Threat Flags

None. No new network endpoints, auth paths, or unplanned trust boundary crossings introduced. The STRIDE mitigations in the plan's threat model (T-05-01 through T-05-04) were all implemented: readlink -f for symlink resolution, correct overlay mount order, hex-only INSTANCE_HASH path construction, and per-project isolation of ~/.claude/projects/.

Self-Check: PASSED

  • FOUND: claudebox.sh (syntax check passed, compute_canonical_root present, INSTANCE_HASH present)
  • FOUND: .planning/REQUIREMENTS.md (INST-01 through INST-04 present)
  • FOUND: commit c5e8cca (mount architecture rewrite)
  • FOUND: commit 6eb3b46 (INST-01 through INST-04 registration)
  • FOUND: commit 4baf576 (/bin/sh symlink fix)