Skip to content

Session Isolation

HoloMUSH is developed primarily by concurrent AI agent sessions (Claude Code) and human contributors working in parallel. Two sessions editing files in the same working tree clobber each other’s uncommitted changes (last write wins on the filesystem), so each session gets its own isolated checkout.

To prevent collisions, every Claude Code session runs in its own git worktree under <repo-parent>/.worktrees/<name>.

task workspace:new -- <name> is the canonical entry point. It:

  • Resolves the main repo from any cwd (via git rev-parse)
  • Runs git fetch origin first so origin/main is fresh
  • Creates the worktree at <parent>/.worktrees/<name> on a new branch <name> off origin/main — or, if a branch <name> already exists, attaches the worktree to that existing branch (so a reused name resumes its work rather than resetting)
  • Is idempotent on re-invocation (just prints the existing path)
Terminal window
task workspace:new -- my-feature
# → /Volumes/Code/github.com/holomush/.worktrees/my-feature

Run task workspace:new -- <name>, then cd into the printed path. Sub-agents launched via the Task tool inherit the parent’s worktree; the parent MUST NOT dispatch parallel Task calls that edit the same files.

Use a claude-iso shell function that wraps task workspace:new + cd + exec claude in one command. Drop one of the snippets below into your shell rc.

Terminal window
# IMPORTANT: `set var (cmd | tail -n 1); or ...` does NOT propagate the
# failure of `cmd` because the pipeline's exit status is `tail`'s, not
# `cmd`'s. We therefore call `task workspace:new` twice — first to check
# the exit status, then again inside command substitution to capture the
# path. The second call is idempotent and just prints the path for an
# existing worktree.
function claude-iso
set name $argv[1]
task workspace:new -- $name >/dev/null
or return $status
set ws (task workspace:new -- $name | tail -n 1)
cd $ws
or return $status
exec claude
end
Terminal window
# Same caveat as fish: $(cmd | tail -n 1) carries tail's exit status, not
# cmd's. Two-call pattern; second call is idempotent.
claude-iso() {
local name="$1"
task workspace:new -- "$name" >/dev/null || return $?
local ws
ws="$(task workspace:new -- "$name" | tail -n 1)"
cd "$ws" || return $?
exec claude
}

Usage:

Terminal window
claude-iso my-feature # creates worktree, cds in, launches claude

New worktrees inherit .claude/ (tracked in git), so SessionStart, UserPromptSubmit, and other Claude Code hooks fire identically in any worktree — no hook re-wiring is needed.

The SessionStart hook also warns if you start a session in the shared main checkout (primary worktree), which is reserved for read-only inspection.

A git worktree carries its own .git file linking back to the main repo, so gh auto-detects the remote — no -R flag is required. You MAY still pass -R holomush/holomush explicitly in scripts for robustness (e.g. gh pr view 123 -R holomush/holomush).

After your branch lands on main, remove the worktree. The leading cd matters — ../.worktrees/<name> is unsafe from any nested cwd:

Terminal window
cd <repo-root>
git worktree remove <repo-parent>/.worktrees/<name>
git branch -d <name>

Stale origin/maintask workspace:new always runs git fetch origin first, so creating a fresh worktree is the easiest way to get a fresh starting point.

Two sessions in the main checkout — exit one, run task workspace:new -- <name> for the other.