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 BoundaryTwo changes in one phase:
-
Plugin mount fix — Replace
~/.claudeboxsymlink approach with direct~/.claudemount + overlays. This fixes all plugins, skills, hooks, MCP configs, commands, agents, keybindings, settings being invisible inside the sandbox. -
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 --gcremoves 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 DecisionsMount Architecture Change (from PLUGIN_MOUNT_FIX.md)
- D-01: Replace
--bind ~/.claudebox ~/.claudebox+--symlink ~/.claudebox ~/.claudewith--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/projectsAFTER the~/.claudebind 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.jsonlAFTER the~/.claudebind mount. This isolates session history. - D-04: Ensure
~/.claudebox/projects/directory and~/.claudebox/history.jsonlfile exist at startup (before bwrap). - D-05:
.credentials.jsonhandling 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.mdalready has what's needed). Must not overwrite user's real~/.claude/CLAUDE.mddestructively.
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-dirresolved to absolute path, falling back to$CWDfor 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-rootplaintext file inside~/.claudebox/projects/<hash>/containing the canonical root path.
GC Mechanism
- D-11:
claudebox --gciterates~/.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
--gcto 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_DIRenv 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.jsonlneeds 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 listPLUGIN_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.jsonstays but mount target changes) - Lines 124-175: SANDBOX.md/CLAUDE.md generation — rethink since
~/.claudeis 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
--gccase BWRAP_ARGSarray with+=appends: add overlay mounts after~/.claudebind- Credential detection pattern (lines 104-122): same pattern
coreutilsalready inruntimeInputs— providessha256sum
Integration Points
- Mount order critical:
--bind ~/.claude ~/.claudefirst, 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)
--gcexits 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.mdto avoid touching user's real~/.claude
- Per-instance
settings.jsonoverride (project-specific model selection) — Phase 7 (Named Profiles) --gc --dry-runto preview what would be removed — scope creepclaudebox --list-instancesto 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