Skip to content

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 ​

DeveloperIssueWorktreeBranchMode
Dev A#42 — Leave workflow.spexso/worktrees/issue-42spexso/issue-42yolo
Dev B#43 — Date picker bug.spexso/worktrees/issue-43spexso/issue-43copilot
Dev C#47 — API refactor.spexso/worktrees/issue-47spexso/issue-47pilot

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:

OutcomeWorktreeWhy
completed (merged)removednormal cleanup in --train-merge
conflict / degradedkeptMR open, human resolves — the worktree holds the conflicting state
gate_failedkeptpost-rebase gate still red after the repair rounds; needs inspection
runner crash / failed / skippedkeptnothing ran cleanup

Listing and reaping leftovers ​

bash
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 remove

Safe-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.