claudebox/.planning/phases/05-per-project-instance-isolation/05-CONTEXT.md
Christopher Mühl 4751161e0f chore: merge executor worktree (phase 05-01)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 09:58:14 +00:00

6.6 KiB

Phase 5: Per-Project Instance Isolation - Context

Gathered: 2026-04-10 (assumptions mode) Updated: 2026-04-13 (PLUGIN_MOUNT_FIX.md integration) Status: Ready for planning

## Phase Boundary

Two changes in one phase:

  1. Plugin mount fix — Replace ~/.claudebox symlink approach with direct ~/.claude mount + overlays. This fixes all plugins, skills, hooks, MCP configs, commands, agents, keybindings, settings being invisible inside the sandbox.

  2. Per-project isolation — Each project directory gets its own conversation history and project-scoped memory. Launching from a git worktree shares state with the main worktree of the same repo. Two concurrent sessions in the same project do not corrupt each other. claudebox --gc removes instance directories whose project root no longer exists on disk.

Credentials (OAuth tokens, API keys) are intentionally shared across all instances — not isolated per project.

## Implementation Decisions

Mount Architecture Change (from PLUGIN_MOUNT_FIX.md)

  • D-01: Replace --bind ~/.claudebox ~/.claudebox + --symlink ~/.claudebox ~/.claude with --bind ~/.claude ~/.claude. This gives the sandbox direct access to all Claude Code config: skills/, commands/, hooks/, plugins/, agents/, mcp.json, settings.json, keybindings.json, get-shit-done/, CLAUDE.md, statusline.sh — no maintenance when new files are added.
  • D-02: Overlay --bind ~/.claudebox/projects ~/.claude/projects AFTER the ~/.claude bind mount (bwrap last-mount-wins). This isolates per-project memory while keeping everything else from real ~/.claude.
  • D-03: Overlay --bind ~/.claudebox/history.jsonl ~/.claude/history.jsonl AFTER the ~/.claude bind mount. This isolates session history.
  • D-04: Ensure ~/.claudebox/projects/ directory and ~/.claudebox/history.jsonl file exist at startup (before bwrap).
  • D-05: .credentials.json handling stays as-is — already separate in current code.
  • D-06: SANDBOX.md and CLAUDE.md management moves from ~/.claudebox/ to ~/.claude/ (or is dropped if real ~/.claude/CLAUDE.md already has what's needed). Must not overwrite user's real ~/.claude/CLAUDE.md destructively.

Per-Project Scoping of projects/ Directory

  • D-07: ~/.claudebox/projects/ contains per-project subdirs keyed by hash: ~/.claudebox/projects/<16-char-hash>/. Inside sandbox, these appear at ~/.claude/projects/<hash>/.
  • D-08: Canonical project root = git rev-parse --git-common-dir resolved to absolute path, falling back to $CWD for non-git directories. All worktrees of the same repo get the same hash.
  • D-09: Hash = SHA-256 of canonical root path, truncated to 16 hex chars.
  • D-10: On instance creation, write project-root plaintext file inside ~/.claudebox/projects/<hash>/ containing the canonical root path.

GC Mechanism

  • D-11: claudebox --gc iterates ~/.claudebox/projects/*/project-root, reads each path, removes any dir whose recorded path no longer exists on disk. Prints removed paths to stderr.
  • D-12: Add --gc to flag-parsing block alongside --yes, --dry-run, --check.

Concurrent Session Safety

  • D-13: No locking needed. Claude Code manages file-level concurrency within its own data dir. Same instance dir shared by concurrent sessions in same project is fine.

CLAUDE_CONFIG_DIR — NOT USED

  • D-14: Previous approach using CLAUDE_CONFIG_DIR env var is abandoned. Direct mount + overlay is simpler, preserves all plugins/skills/hooks, and requires no per-instance directory tree duplication.

Claude's Discretion

  • Exact hash truncation length (16 chars recommended)
  • Whether to print instance path at launch (verbose addition later)
  • SANDBOX.md strategy: whether to keep writing it to ~/.claudebox/ and bind-mount it, or write to ~/.claude/ directly
  • Whether history.jsonl needs per-project hashing too or one shared sandbox history is fine

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Codebase

  • claudebox.sh — full script; flag parsing (lines 1-18), BWRAP_ARGS construction (lines 364-401), credential mount logic (lines 104-122), SANDBOX.md/CLAUDE.md management (lines 124-175), dry-run echo block (lines 318-361)
  • flake.nix — Nix packaging; runtimeInputs list
  • PLUGIN_MOUNT_FIX.md — the architectural change driving this update

Requirements

  • .planning/REQUIREMENTS.md — INST-01 through INST-04 need to be added during planning
  • .planning/ROADMAP.md — Phase 5 success criteria (lines 44-53)

</canonical_refs>

<code_context>

Existing Code Insights

What Must Change

  • Lines 383-384: --bind "$HOME/.claudebox" "$HOME/.claudebox" + --symlink "$HOME/.claudebox" "$HOME/.claude"--bind "$HOME/.claude" "$HOME/.claude" + overlay mounts
  • Lines 348-349 (dry-run): Same change mirrored in dry-run output
  • Lines 104-112: Credential file path may need adjusting (~/.claudebox/.credentials.json stays but mount target changes)
  • Lines 124-175: SANDBOX.md/CLAUDE.md generation — rethink since ~/.claude is now real
  • Lines 276-283 (print_audit): Update mount display to reflect new architecture
  • Line 102: mkdir -p "$HOME/.claudebox" — also ensure projects/ and history.jsonl exist

Reusable Assets

  • Flag parsing block (lines 1-18): add --gc case
  • BWRAP_ARGS array with += appends: add overlay mounts after ~/.claude bind
  • Credential detection pattern (lines 104-122): same pattern
  • coreutils already in runtimeInputs — provides sha256sum

Integration Points

  • Mount order critical: --bind ~/.claude ~/.claude first, then overlays for projects/ and history.jsonl
  • Dry-run block must mirror all changes
  • print_audit() must reflect new mount layout

</code_context>

## Specific Ideas
  • Per-project dirs at ~/.claudebox/projects/<16-char-hash>/ — human-debuggable length
  • GC prints removed paths to stderr (consistent with claudebox's stderr-only output convention)
  • --gc exits after running, does not launch Claude (same pattern as --check)
  • SANDBOX.md could be bind-mounted as single file from ~/.claudebox/SANDBOX.md~/.claude/SANDBOX.md to avoid touching user's real ~/.claude
## Deferred Ideas
  • Per-instance settings.json override (project-specific model selection) — Phase 7 (Named Profiles)
  • --gc --dry-run to preview what would be removed — scope creep
  • claudebox --list-instances to show all instances with their project roots — nice-to-have

Phase: 05-per-project-instance-isolation Context gathered: 2026-04-10, updated 2026-04-13