123 lines
6.6 KiB
Markdown
123 lines
6.6 KiB
Markdown
# 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
|
|
|
|
<domain>
|
|
## 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.
|
|
|
|
</domain>
|
|
|
|
<decisions>
|
|
## 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
|
|
|
|
</decisions>
|
|
|
|
<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>
|
|
|
|
<specifics>
|
|
## 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`
|
|
|
|
</specifics>
|
|
|
|
<deferred>
|
|
## 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
|
|
|
|
</deferred>
|
|
|
|
---
|
|
|
|
*Phase: 05-per-project-instance-isolation*
|
|
*Context gathered: 2026-04-10, updated 2026-04-13*
|