Skip to content

Parallel Session Grid (isolated worktrees)

Run multiple Claude sessions in parallel without them tangling. Each session gets its own git worktree (isolated index + files), so two sessions can never race on one working tree. Backed by scripts/wt-grid.ps1; driven by four PowerShell aliases.

Why not the old 8w/8s grid? Those open every pane in the same main tree, which causes the 2026-06-05 collision class (a sibling's pre-commit stashes your unstaged edits, two sessions conflict mid-edit, pushes get blocked). The grid here makes that impossible — any real overlap becomes a safe merge conflict at merge time, never a live race that loses work. Policy: .claude/rules/concurrent-sessions.md.

Aliases (defined in your PowerShell profile)

Alias Action Common flags
8wt Launch grid: pane 1 = main tree (servers + coordinator), panes 2..N = isolated worktrees -Tasks <file>, -Panes <2..8>
8wts Status: which slots exist, clean/dirty, commits ahead
8wtm Merge every wt/slot* branch into your current branch -Into <branch>
8wtd Tear down all slots (safe) + delete merged branches -Force (discard unmerged)

Every pane runs Opus: the launcher exports ANTHROPIC_MODEL=opus, which outranks the repo's checked-in .claude/settings.json "model": "opusplan" (that setting would otherwise plan on Opus and execute on Sonnet). There is no Sonnet grid — -Model sonnet is rejected.

If the aliases aren't found, reload the profile: . $PROFILE

First-time shakeout (do this once)

. $PROFILE          # load the aliases
8wt -Panes 3        # small grid, no tasks -> new wt window, panes in slot2/slot3
8wts                # from your original terminal: confirm slot2/slot3 show 'clean'
8wtd                # confirm clean teardown; 8wts should then show nothing

If panes open in the right directories and teardown is clean, it's ready.

Daily use

1. Write a task manifest (one task per line)

Blank lines and lines starting with # are ignored. Line 1 -> slot 2, line 2 -> slot 3, and so on. Save anywhere, e.g. tasks.txt:

# line 1 -> slot 2, line 2 -> slot 3, ...
Fix all TS errors under frontend/src/services/stackup
Add a golden recording for the run_pdn_analysis tool
Update docs/guides/AI_NATIVE_SHELL.md for the new export formats

2. Launch the seeded grid

8wt -Tasks tasks.txt

Each seeded pane writes its line to _TASK.md in its worktree and auto-starts Claude already told to read it and do the work — no typing or pasting. Panes beyond the task count open a plain session. (Seeded slots run in acceptEdits without plan-mode so they execute; an unseeded 8wt keeps opus + plan-mode.)

3. Merge the work back

From your main-tree / coordinator terminal:

8wtm

Clean slots merge into your current branch; conflicts are aborted-and-reported for manual resolution; dirty/incomplete slots are skipped.

Then it tests the combined result. Each slot only ever tested its own change, alone. When at least one slot merged, 8wtm runs scripts/grid-postmerge-check.ps1 on everything the round added:

The round changed… What runs
anything under frontend/ (a deletion counts) tsc --noEmit on the whole project + vitest run --changed <before> (only the tests affected)
a backend .py file pytest on the test files the round added or edited
backend code but no backend test file nothing — it prints a NOTE saying so

It is targeted on purpose: the main tree is shared with other sessions, and the full suites stay the nightly's job. A failure prints POST-MERGE CHECK: FAIL and makes 8wtm exit 1 — the merges are kept, never undone, so fix forward before pushing. If HEAD moves during the run (another session committed into the tree), the result is reported void. Measured 2026-09-23 on real merges: 4–5 s when only two backend test files changed; 79 s when a frontend change pulled in 50 affected test files (tsc 21 s + vitest 53 s + pytest 4 s).

  • Skip it: 8wtm -NoCheck.
  • Re-run it by hand (for example after resolving a conflict yourself): powershell -NoProfile -File scripts\grid-postmerge-check.ps1 -Since <sha before the round> — 8wtm prints the exact command when a check fails.

4. Clean up

8wtd

Or: steps 3 and 4 in one command

8wtm -Finish

Merges and tests as in step 3, then archives the finished task text (8wta), commits only tasks.txt + tasks.archive.txt, and tears the grid down (8wtd). Before this it was four hand steps with the # DONE marks left uncommitted in between.

It stops before archiving — keeping every slot and exiting 1 — and says why, when anything needs you:

Stops when… Why it must stop
a slot was skipped as dirty teardown force-removes the checkout, so its unsaved edits would be deleted
a slot conflicted its branch still needs a hand merge
the post-merge check failed or was void fix it while the slots still exist

Two more rules it follows:

  • It never commits task lines you were still writing. If tasks.txt or tasks.archive.txt already had unsaved edits before the merge, it archives and tears down but leaves both files uncommitted and says so.
  • ⚠ A re-run after a stop merges nothing new, so the check does not run again. Confirm your fix with the printed grid-postmerge-check.ps1 -Since … command first, then run 8wtm -Finish again.

Tested 2026-09-23 on throwaway slots: a clean round (merged, archived, committed, torn down, exit 0), a dirty slot, a failing type check (both stopped with exit 1 and kept the slot) and pre-edited task files (not committed).

Two rules that matter

  1. Commit or 8wtm before 8wtd. Teardown force-removes the worktree checkout, so uncommitted edits in a slot are lost. Committed work survives on its wt/slot* branch even after teardown. (The seeded prompt tells Claude to commit, so the automated flow is safe.)
  2. Write non-overlapping tasks. Isolation removes the live race but not scope overlap — two slots editing the same file collide at 8wtm as an ordinary merge conflict. Partitioning the work is the one piece only you can decide.

Troubleshooting

Symptom Cause / fix
8wt errors Slot worktree exists / Branch wt/slotN exists A previous grid wasn't torn down. Run 8wtd (add -Force to discard unmerged branches).
Aliases not recognized . $PROFILE, or open a new terminal.
A pane opened in the wrong directory Likely the wt argument string; check scripts/wt-grid.ps1 Do-Launch.
Slot has commits but 8wtm says "nothing to merge" It compares against your current branch — make sure you're on the same base branch the grid was launched from.
8wtm ends with POST-MERGE CHECK: FAIL Two slots that each passed alone break together (or one slot's check was skipped). The merges are kept; read the failing step's output above the summary, fix, then re-run the printed grid-postmerge-check.ps1 -Since … command.
8wtm -Finish says finish STOPPED … It names the reason (dirty slot, conflicted slot, or failed check). Every slot is kept; fix that one thing, then run 8wtm -Finish again.
Summary says the verdict is VOID HEAD moved while the check ran — another session committed into the main tree. Re-run the printed command once it is quiet.

How it works (internals)

scripts/wt-grid.ps1 delegates all worktree create/teardown to scripts/worktree-session.ps1 (the proven, footgun-protected script) and never runs git worktree remove itself. Worktrees are named pcb-wt-slotN on branch wt/slotN, with backend/venv and frontend/node_modules junctioned to the main tree (usable in seconds, no installs) and the root .env copied. The dev servers (ports 8000/5180) always run from the main tree only.