Branch the session tree
Decide between /tree, /fork and /clone, and see a session as a tree where an abandoned branch is never sent and never gone.
A stored session is a tree of entries linked by id and parentId, and the
current position is the leaf. /tree moves inside that tree, /fork starts a new
session from an earlier prompt, and /clone copies the active branch into a new
session. The trace below is illustrative; the claims it draws are the ones
branching.test.ts asserts on 1.0.4, with /fork and /clone on the shipped
binary.
Choose the command
| Action | Result | Use it when |
|---|---|---|
/tree |
moves within the current session file | related alternatives belong together |
/fork |
new session from an earlier user prompt | the alternative becomes separate work |
/clone |
copy of the active branch in a new session | you want a separate copy of current state |
A tiny branch, as entries
The shared history is linear until question B is edited. Submitting the edited prompt creates a sibling — two children of the same parent, one session file. The abandoned branch is not sent, and is not gone:
{"type":"session","version":3,"id":"sess-a1","timestamp":"2026-10-01T09:00:00.000Z"}
{"type":"message","id":"a-user","parentId":null,"timestamp":"2026-10-01T09:00:01.000Z","message":{"role":"user","content":"question A"}}
{"type":"message","id":"a-bot","parentId":"a-user","timestamp":"2026-10-01T09:00:02.000Z","message":{"role":"assistant","content":"answer A"}}
{"type":"message","id":"b-user","parentId":"a-bot","timestamp":"2026-10-01T09:00:03.000Z","message":{"role":"user","content":"question B"}}
{"type":"message","id":"b-bot","parentId":"b-user","timestamp":"2026-10-01T09:00:04.000Z","message":{"role":"assistant","content":"answer B"}}
{"type":"message","id":"b-edit","parentId":"a-bot","timestamp":"2026-10-01T09:00:05.000Z","message":{"role":"user","content":"question B, edited"}}
{"type":"branch_summary","id":"sum-1","parentId":"a-bot","timestamp":"2026-10-01T09:00:06.000Z","summary":"Summary of the abandoned path: asked B and C.","fromId":"b-bot"}b-user and b-edit hang from the same parent, a-bot. A navigation with
summarize enabled wrote the branch_summary entry just below them — the trace
compresses two of the test’s interactions into one file. parentId is where you
land, fromId is the leaf you left, the abandoned entries stay in the tree, and
getTree() reports both branches under their shared parent. Labels are bookmarks:
appendLabelChange puts a label on an entry, getTree() shows it, and setting
the label to undefined clears it.
What /tree does to a selection
| You select | Result |
|---|---|
| a user message | its text returns to the editor; the leaf moves to that message’s parent |
| an assistant response (or other entry) | Pi continues after it with an empty editor |
Mechanism and limitations
Documented: the entry tree (id/parentId — the shared session-file format is
Chapter 27’s declaration), the /tree selection rules, labels, and get_fork_messages
/ fork / clone as RPC commands. Observed: branching.test.ts runs the
harness and the shipped binary with the faux provider — navigateTree moves the
leaf, edited prompts make siblings in one file, abandoned branches are absent from
requests but present in session entries, the summary entry’s fromId/parentId
point to the right ends, getTree() has two children, and over RPC a fork starts
a new session file whose session header carries parentSession — the only
durable record of where it came from — while clone copies the active branch.
The trace is a drawing, not a transcript: ids are shortened and fields trimmed. A
/fork’s new file has no record of what it left — no branch summary exists there —
so only /tree can hand you a summary of the abandoned path. This page shows the
storage model around a model, not a real model choosing a branch.
Understand this example
Copy this prompt into your AI tool. No code runs here.
Apply this example
Copy this prompt into your AI tool. No code runs here.