Fork & compare
A fork is a new session that starts from a point in an existing one. It gets the conversation up to that point and the code as it stood at that point, on its own branch in its own worktree. The original keeps running untouched.
Fork once to try a different idea without losing the current one. Fork three times with different instructions to get three attempts at the same problem, then keep the best.
Fork a session
Section titled “Fork a session”You can fork from any of these places:
| From | How |
|---|---|
| The session on screen | ⌘⇧F (Ctrl+Shift+F off macOS), or Fork this session in the ⌘K palette. |
| The sidebar | The ⑂ button on a session’s row. |
| The Fleet | Select a session and press f. |
| A specific turn | Open the Inspector’s Transcript tab and hover a message. ⑂ Fork on an assistant message forks after that turn. ⑂ Fork before on one of your prompts forks just before it. |
The sidebar’s ⑂ is enabled once the session has started a conversation.
All of these open the same Fork dialog. It names the point you’re forking from, such as after turn 3 · “Add the retry wrapper”, or from the latest turn.
- How many: choose 1, 2, 3 or 5, or type any number up to 8.
- First message (optional): the fork’s opening prompt, sent once its agent is up.
- Send the message right away: on by default. Turn it off to leave the message in the fork’s composer for you to send.
Press ⌘↵ to fork. With one fork, spwn opens the new session. With several, they open side by side in Compare.
Fork before a prompt
Section titled “Fork before a prompt”⑂ Fork before on one of your own messages forks the conversation as it was just before you sent it. The prompt comes back pre-filled in the dialog, so you can edit it and send a different version. It’s the quickest way to ask “what if I’d said it differently?”
What comes along
Section titled “What comes along”A fork from the latest turn resumes the parent’s full conversation, and its branch starts from the parent’s branch as it is now.
A fork from an earlier turn moves both halves back together:
- The conversation. spwn writes a copy of the parent’s transcript cut off at the end of that turn, and the fork resumes the copy. The parent’s own history is never edited. An anchor in the middle of a turn is moved forward to the end of that turn, because a tool call without its result can’t be resumed. The copy is deleted once every fork has a transcript of its own.
- The code. The fork’s worktree starts at the commit that turn left behind, not
at the parent’s latest commit. spwn records the
HEADof each session when a turn’s hooks finish. For older turns it falls back to thespwn turn <id>commit subjects, and then to the nearest earlier turn that has either. If no turn up to that point changed anything, the fork starts where the parent started.
So a fork from turn 3 sees turn 3’s code and remembers turn 3’s conversation, not turn 9’s code with turn 3’s memory.
A fork’s base branch is its parent’s branch. It merges back into the session it
came from, not straight into main. See Forks merge one rung up.
Best-of-N
Section titled “Best-of-N”Set How many above 1 and every fork gets the same first message by default. The
forks are named after the parent with a letter: auth-fix ⑂a, auth-fix ⑂b,
auth-fix ⑂c. (A single fork is auth-fix ⑂.)
Untick Same prompt for every fork to give each fork its own row:
- Title: optional. Leave it blank to keep the lettered name.
- Agent: defaults to the parent’s agent. If you choose a different agent, that fork starts fresh, with no history. It gets the code at that turn, but another agent can’t read this one’s conversation.
- Prompt: what this fork should try.
⑂a "Keep the old API and add an adapter."⑂b "Change the API and update every caller."⑂c "Find out whether we need this endpoint at all."Forks made together share a batch. That’s what Compare opens, and what pick chooses among.
Lineage in the sidebar
Section titled “Lineage in the sidebar”Forks nest under the session they came from. A root session has a ✦ and each fork has a ↳, indented one level per generation. A session with forks shows how many and has a twisty to collapse them.
The Inspector’s Overview tab draws the whole Fork family. Each row shows the fork point (@t3 means forked after turn 3), a ★ on the picked attempt, and what each one is doing. When there’s more than one attempt to compare, the header has a Compare N button.
Compare side by side
Section titled “Compare side by side”Compare opens:
- automatically, after you fork more than one at a time;
- from Compare N in the Fork family;
- from the Fleet: select a session and press c.
Each lane is one attempt. A lane shows:
- the title and fork point;
- its cost so far;
- what it’s doing now, and its last reply;
- ±N files, ↑ahead, and ↓behind its base;
- ⚠ conflicts with base when merging it would conflict;
- ◑ for another session changing the same files;
- a diff.
The diff starts against the base. Switch it to any sibling to read how two attempts differ, instead of reading each one in full.
Check it merges & passes merges the attempt with its base in a scratch worktree and
runs your session-integrate hooks on the result. A check that ran before the base moved
is marked (stale). See Verify.
| Key | Action |
|---|---|
| h / ←, l / → | Previous / next lane |
| p | Pick the focused attempt |
| v | Check it merges and passes |
| d | Cycle the diff: against the base, then each sibling in turn |
| ↵ / o | Open the focused attempt |
Land the winner, delete the rest
Section titled “Land the winner, delete the rest”- Pick the attempt you want with p or its ☆. Picking one un-picks the others in the same batch.
- Land it with the Land button on its lane. This puts it in the land order, which syncs it with its base, hands any conflict back to its agent, runs the checks and merges it. The button says In the land order once it’s queued.
- Discard the others… in the Compare header deletes every attempt except the picked one. Each delete asks first, and names any unmerged commits or uncommitted changes it would throw away. Cancel one and the rest stop there.
Forks merge one rung up
Section titled “Forks merge one rung up”Because a fork’s base is its parent’s branch, landing a fork merges it into the
parent session’s branch. To get it into main, land the parent afterwards. For a
fork, the Merge dialog says so and shows the full route, such as
spwn/9b41e0d2 → spwn/3f9c2a1b → main. Folding each fork into its parent keeps every
merge small.
If you want an attempt to go straight to main, fork from a session whose base is
main. Or merge the fork’s branch by hand:
git checkout maingit merge spwn/9b41e0d2