Worktree Management
Spexso enforces one worktree per issue. This guarantees that multiple developers — and multiple marathon runners — can work on the same repo simultaneously without file conflicts. Each worktree gets its own branch, its own Claude Code session context, and its own isolated file system.
Worktree Layout
your-project/ # Main worktree (main branch)
├── .spexso/
│ └── worktrees/
│ ├── issue-42/ # Dev A's workspace
│ │ └── (full repo checkout on branch spexso/issue-42)
│ ├── issue-43/ # Dev B's workspace
│ │ └── (full repo checkout on branch spexso/issue-43)
│ └── issue-47/ # Dev C's workspace
│ └── (full repo checkout on branch spexso/issue-47)Multi-Developer Scenario
| Developer | Issue | Worktree | Branch | Mode |
|---|---|---|---|---|
| Dev A | #42 — Leave workflow | .spexso/worktrees/issue-42 | spexso/issue-42 | yolo |
| Dev B | #43 — Date picker bug | .spexso/worktrees/issue-43 | spexso/issue-43 | copilot |
| Dev C | #47 — API refactor | .spexso/worktrees/issue-47 | spexso/issue-47 | pilot |
All three developers work simultaneously. Zero file conflicts during development. Merge conflicts are handled at MR merge time — by then, code has been reviewed and tested.
Enforcement rule
Right after git worktree add, /spexso-start runs npm ci in the new worktree when it has a package-lock.json. Without its own node_modules, Node resolves the main checkout's one level up (or nothing), and a real Cannot find module passes for an environmental false-fail.
/spexso-start refuses to create a worktree if one already exists for that issue. One issue = one worktree = one developer. If issue #42 already has a worktree, the command outputs: "Issue #42 already has an active worktree. Use /spexso-finish or manually clean up."
Marathon: N concurrent worktrees per wave
/spexso-marathon is not one-per-developer: a single orchestrator holds N worktrees at once — one per runner in the current wave. Runners end with /spexso-finish --train (MR created, worktree kept), and the merge train integrates them one at a time with --train-merge, removing each worktree after its merge.
Some outcomes leave a worktree behind on purpose — the code inside is the diagnosis material:
| Outcome | Worktree | Why |
|---|---|---|
completed (merged) | removed | normal cleanup in --train-merge |
conflict / degraded | kept | MR open, human resolves — the worktree holds the conflicting state |
gate_failed | kept | post-rebase gate still red after the repair rounds; needs inspection |
runner crash / failed / skipped | kept | nothing ran cleanup |
Listing and reaping leftovers
npx spexso worktrees # list: id, branch, dirty?, index stage, verdict
npx spexso worktrees reap # dry-run: prints what WOULD be removed and why
npx spexso worktrees reap --force # actually removeSafe-to-reap = the issue is closed or stage::ship in the index, or the directory no longer has a matching branch (orphan). Anything dirty or in stage::build/stage::review is printed as kept: <reason> and never auto-removed — same for an unknown state when the index is missing (run npx spexso sync first). Removal uses the same Windows-safe fallback as the finish flow (git worktree remove --force, else rm -rf + git worktree prune).
Crash recovery
Issue stuck at stage::review with an open MR after a crash? The merge train died mid-flight: re-run /spexso-finish --train-merge {id} --mr {mr_id} to integrate it, then npx spexso worktrees reap for the leftovers.