Session Tree

The /tree command provides visual navigation through your session's branching history. Sessions form a tree structure where each message is a node, and branching creates alternate paths from any point.

Overview

When you type /tree in interactive mode, a tree selector opens showing all entries in your session. You can navigate to any point in the tree, effectively rewinding to that state and starting a new branch from there.

This is different from /fork, which creates a new session file containing only the path up to the selected point. /tree stays in the same session file and simply moves the leaf pointer, creating a new branch within the existing tree.

The tree selector uses depth-first traversal to display the session tree. Each entry is shown with its type and a preview of its content.

Keyboard Controls

KeyAction
Up / DownMove between entries
Ctrl+UFilter to show only user messages
Ctrl+OShow all entry types
EnterSelect the highlighted entry
EscapeCancel and return to editor

Selection Behavior

The behavior when selecting an entry depends on its type:

Entry TypeBehavior
User messageNavigates to the parent of the user message. The user message text is placed in the editor for re-editing.
Custom messageNavigates to the parent of the custom message. The message text is placed in the editor.
Other messages (assistant, tool result, etc.)Navigates directly to the selected entry.
Root (first entry)Resets the leaf to null, allowing you to start a completely new conversation from scratch.

When navigating to a user message's parent, the original user message text is pre-filled in the editor. This lets you modify and re-send the message, creating a new branch from that point.

Branch Summarization

When navigating away from an existing branch, you have options for handling the abandoned branch's context:

  1. Skip - Navigate without summarizing. The abandoned branch remains in the session but its context is not carried forward.
  2. Auto-summarize - The LLM generates a structured summary of the abandoned branch. This summary is stored as a BranchSummaryEntry and injected into the LLM context on future turns.
  3. Custom instructions - Provide specific instructions for the summarizer to focus on particular aspects of the abandoned branch.

BranchSummaryEntry

When summarization is chosen, a BranchSummaryEntry is appended to the session:

interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
  type: "branch_summary";
  fromId: string; // Entry ID where the branch was abandoned
  summary: string; // Structured summary text
  details?: T; // File tracking data (readFiles, modifiedFiles)
  fromHook?: boolean; // True if generated by an extension
}

The summary follows a structured format including:

  • Goal - What the conversation was trying to accomplish
  • Progress - What was completed
  • Key Decisions - Important choices made
  • Critical Context - Information needed going forward
  • read-files / modified-files - File operations tracked

This summary is injected into the LLM context as a BranchSummaryMessage, prefixed with:

The following is a summary of a branch that this conversation came back from:

<summary>
...summary content...
</summary>

Difference from /fork

Feature/tree/fork
FileSame session fileNew session file
HistoryAll branches preserved in one fileNew file contains only the selected path
NavigationMoves leaf pointer within treeCreates independent session
Branch contextOptional summarization of abandoned branchNo summarization
Use caseExploring alternatives within a sessionStarting a clean session from a checkpoint

Extension Hooks

Extensions can intercept and customize tree navigation via two events:

session_before_tree

Fired before tree navigation begins. Extensions can cancel or modify the navigation.

pi.on("session_before_tree", async (event) => {
  // event.targetId - The entry ID being navigated to
  // event.cancel() - Cancel the navigation
  // event.setSummarize(boolean) - Override whether to summarize
  // event.setCustomInstructions(string) - Set custom summarization instructions
  // event.setReplaceInstructions(boolean) - Replace default prompt instead of appending
});

session_tree

Fired after tree navigation completes. Extensions can react to the navigation result.

pi.on("session_tree", async (event) => {
  // event.targetId - The entry ID that was navigated to
  // event.summaryEntry - The BranchSummaryEntry, if summarization occurred
  // event.editorText - Text placed in editor, if any
  // event.cancelled - Whether navigation was cancelled
  // event.aborted - Whether summarization was aborted
});

Programmatic Navigation

Use AgentSession.navigateTree() for programmatic tree navigation:

const result = await session.navigateTree(targetId, {
  summarize: true, // Whether to summarize abandoned branch
  customInstructions: "Focus on API changes", // Optional custom focus
  replaceInstructions: false, // Append to default prompt (default)
  label: "checkpoint-v2", // Optional label for the branch summary
});

// result.editorText - Text for editor pre-fill (if user message selected)
// result.cancelled - Whether navigation was cancelled by extension
// result.aborted - Whether summarization was aborted
// result.summaryEntry - The BranchSummaryEntry, if created

You can also get the tree structure programmatically:

const tree: SessionTreeNode[] = session.sessionManager.getTree();

interface SessionTreeNode {
  entry: SessionEntry;
  children: SessionTreeNode[];
  label?: string;
}