diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index aafc1a64..10cdc2c0 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -218,7 +218,7 @@ Configure delivery in [settings](docs/settings.md): `steeringMode` and `followUp ## Sessions -Sessions are stored as JSONL files with a tree structure. Each entry has an `id` and `parentId`, enabling in-place branching without creating new files. See [docs/session.md](docs/session.md) for file format. +Sessions are stored as JSONL files with a tree structure. Each entry has an `id` and `parentId`, enabling in-place branching without creating new files. See [docs/session-format.md](docs/session-format.md) for file format. ### Management diff --git a/packages/coding-agent/docs/docs.json b/packages/coding-agent/docs/docs.json index 34d12d37..f96321d9 100644 --- a/packages/coding-agent/docs/docs.json +++ b/packages/coding-agent/docs/docs.json @@ -29,11 +29,7 @@ }, { "title": "Sessions", - "path": "session.md" - }, - { - "title": "Session Tree", - "path": "tree.md" + "path": "sessions.md" }, { "title": "Compaction", @@ -74,6 +70,15 @@ } ] }, + { + "title": "Reference", + "items": [ + { + "title": "Session Format", + "path": "session-format.md" + } + ] + }, { "title": "Programmatic Usage", "items": [ @@ -129,5 +134,15 @@ } ] } + ], + "redirects": [ + { + "from": "session.md", + "to": "session-format.md" + }, + { + "from": "tree.md", + "to": "sessions.md" + } ] } diff --git a/packages/coding-agent/docs/extensions.md b/packages/coding-agent/docs/extensions.md index 0bef2cfc..dbb4426c 100644 --- a/packages/coding-agent/docs/extensions.md +++ b/packages/coding-agent/docs/extensions.md @@ -350,7 +350,7 @@ pi.on("resources_discover", async (event, _ctx) => { ### Session Events -See [session.md](session.md) for session storage internals and the SessionManager API. +See [Session Format](session-format.md) for session storage internals and the SessionManager API. #### session_start @@ -429,7 +429,7 @@ pi.on("session_compact", async (event, ctx) => { #### session_before_tree / session_tree -Fired on `/tree` navigation. See [tree.md](tree.md) for tree navigation concepts. +Fired on `/tree` navigation. See [Sessions](sessions.md) for tree navigation concepts. ```typescript pi.on("session_before_tree", async (event, ctx) => { @@ -569,7 +569,7 @@ pi.on("tool_execution_end", async (event, ctx) => { #### context -Fired before each LLM call. Modify messages non-destructively. See [session.md](session.md) for message types. +Fired before each LLM call. Modify messages non-destructively. See [Session Format](session-format.md) for message types. ```typescript pi.on("context", async (event, ctx) => { @@ -833,7 +833,7 @@ Current working directory. ### ctx.sessionManager -Read-only access to session state. See [session.md](session.md) for the full SessionManager API and entry types. +Read-only access to session state. See [Session Format](session-format.md) for the full SessionManager API and entry types. For `tool_call`, this state is synchronized through the current assistant message before handlers run. In parallel tool execution mode it is still not guaranteed to include sibling tool results from the same assistant message. diff --git a/packages/coding-agent/docs/index.md b/packages/coding-agent/docs/index.md index dc55a895..d119c0ab 100644 --- a/packages/coding-agent/docs/index.md +++ b/packages/coding-agent/docs/index.md @@ -27,8 +27,7 @@ For the full first-run flow, see [Quickstart](quickstart.md). - [Providers](providers.md) - subscription and API-key setup for built-in providers. - [Settings](settings.md) - global and project settings. - [Keybindings](keybindings.md) - default shortcuts and custom keybindings. -- [Sessions](session.md) - session storage format and session files. -- [Session tree](tree.md) - branching and navigating previous turns. +- [Sessions](sessions.md) - session management, branching, and tree navigation. - [Compaction](compaction.md) - context compaction and branch summarization. ## Customization @@ -48,6 +47,10 @@ For the full first-run flow, see [Quickstart](quickstart.md). - [JSON event stream mode](json.md) - print mode with structured events. - [TUI components](tui.md) - build custom terminal UI for extensions. +## Reference + +- [Session format](session-format.md) - JSONL session file format, entry types, and SessionManager API. + ## Platform setup - [Windows](windows.md) diff --git a/packages/coding-agent/docs/sdk.md b/packages/coding-agent/docs/sdk.md index d84ca0a1..64d1374d 100644 --- a/packages/coding-agent/docs/sdk.md +++ b/packages/coding-agent/docs/sdk.md @@ -779,7 +779,7 @@ sm.branchWithSummary(id, "Summary..."); // Branch with context summary sm.createBranchedSession(leafId); // Extract path to new file ``` -> See [examples/sdk/11-sessions.ts](../examples/sdk/11-sessions.ts) and [docs/session.md](session.md) +> See [examples/sdk/11-sessions.ts](../examples/sdk/11-sessions.ts) and [Session Format](session-format.md) ### Settings Management diff --git a/packages/coding-agent/docs/session.md b/packages/coding-agent/docs/session-format.md similarity index 100% rename from packages/coding-agent/docs/session.md rename to packages/coding-agent/docs/session-format.md diff --git a/packages/coding-agent/docs/sessions.md b/packages/coding-agent/docs/sessions.md new file mode 100644 index 00000000..d262f853 --- /dev/null +++ b/packages/coding-agent/docs/sessions.md @@ -0,0 +1,137 @@ +# Sessions + +Pi saves conversations as sessions so you can continue work, branch from earlier turns, and revisit previous paths. + +## Session Storage + +Sessions auto-save to `~/.pi/agent/sessions/`, organized by working directory. Each session is a JSONL file with a tree structure. + +```bash +pi -c # Continue most recent session +pi -r # Browse and select from past sessions +pi --no-session # Ephemeral mode; do not save +pi --session # Use a specific session file or partial session ID +pi --fork # Fork a session file or partial session ID into a new session +``` + +Use `/session` in interactive mode to see the current session file, session ID, message count, tokens, and cost. + +For the JSONL file format and SessionManager API, see [Session Format](session-format.md). + +## Session Commands + +| Command | Description | +|---------|-------------| +| `/resume` | Browse and select previous sessions | +| `/new` | Start a new session | +| `/name ` | Set the current session display name | +| `/session` | Show session info | +| `/tree` | Navigate the current session tree | +| `/fork` | Create a new session from a previous user message | +| `/clone` | Duplicate the current active branch into a new session | +| `/compact [prompt]` | Summarize older context; see [Compaction](compaction.md) | +| `/export [file]` | Export session to HTML | +| `/share` | Upload as private GitHub gist with shareable HTML link | + +## Resuming and Deleting Sessions + +`/resume` opens an interactive session picker for the current project. `pi -r` opens the same picker at startup. + +In the picker you can: + +- search by typing +- toggle path display with Ctrl+P +- toggle sort mode with Ctrl+S +- filter to named sessions with Ctrl+N +- rename with Ctrl+R +- delete with Ctrl+D, then confirm + +When available, pi uses the `trash` CLI for deletion instead of permanently removing files. + +## Naming Sessions + +Use `/name ` to set a human-readable session name: + +```text +/name Refactor auth module +``` + +Named sessions are easier to find in `/resume` and `pi -r`. + +## Branching with `/tree` + +Sessions are stored as trees. Every entry has an `id` and `parentId`, and the current position is the active leaf. `/tree` lets you jump to any previous point and continue from there without creating a new file. + +

Tree View

+ +Example shape: + +```text +├─ user: "Hello, can you help..." +│ └─ assistant: "Of course! I can..." +│ ├─ user: "Let's try approach A..." +│ │ └─ assistant: "For approach A..." +│ │ └─ user: "That worked..." ← active +│ └─ user: "Actually, approach B..." +│ └─ assistant: "For approach B..." +``` + +### Tree Controls + +| Key | Action | +|-----|--------| +| ↑/↓ | Navigate visible entries | +| ←/→ | Page up/down | +| Ctrl+←/Ctrl+→ or Alt+←/Alt+→ | Fold/unfold or jump between branch segments | +| Shift+L | Set or clear a label on the selected entry | +| Shift+T | Toggle label timestamps | +| Enter | Select entry | +| Escape/Ctrl+C | Cancel | +| Ctrl+O | Cycle filter mode | + +Filter modes are: default, no-tools, user-only, labeled-only, and all. Configure the default with `treeFilterMode` in [Settings](settings.md). + +### Selection Behavior + +Selecting a user or custom message: + +1. Moves the leaf to the selected message's parent. +2. Places the selected message text in the editor. +3. Lets you edit and resubmit, creating a new branch. + +Selecting an assistant, tool, compaction, or other non-user entry: + +1. Moves the leaf to that entry. +2. Leaves the editor empty. +3. Lets you continue from that point. + +Selecting the root user message resets the leaf to an empty conversation and places the original prompt in the editor. + +## `/tree`, `/fork`, and `/clone` + +| Feature | `/tree` | `/fork` | `/clone` | +|---------|---------|---------|----------| +| Output | Same session file | New session file | New session file | +| View | Full tree | User-message selector | Current active branch | +| Typical use | Explore alternatives in place | Start a new session from an earlier prompt | Duplicate current work before continuing | +| Summary | Optional branch summary | None | None | + +Use `/tree` when you want to keep alternatives together. Use `/fork` or `/clone` when you want a separate session file. + +## Branch Summaries + +When `/tree` switches away from one branch to another, pi can summarize the abandoned branch and attach that summary at the new position. This preserves important context from the path you left without replaying the whole branch. + +When prompted, choose one of: + +1. no summary +2. summarize with the default prompt +3. summarize with custom focus instructions + +See [Compaction](compaction.md) for branch summarization internals and extension hooks. + +## Session Format + +Session files are JSONL and contain message entries, model changes, thinking-level changes, labels, compactions, branch summaries, and extension entries. + +For parsers, extensions, SDK usage, and the full SessionManager API, see [Session Format](session-format.md). diff --git a/packages/coding-agent/docs/tree.md b/packages/coding-agent/docs/tree.md deleted file mode 100644 index afa85f62..00000000 --- a/packages/coding-agent/docs/tree.md +++ /dev/null @@ -1,233 +0,0 @@ -# Session Tree Navigation - -The `/tree` command provides tree-based navigation of the session history. - -## Overview - -Sessions are stored as trees where each entry has an `id` and `parentId`. The "leaf" pointer tracks the current position. `/tree` lets you navigate to any point and optionally summarize the branch you're leaving. - -### Comparison with `/fork` - -| Feature | `/fork` | `/tree` | -|---------|---------|---------| -| View | Flat list of user messages | Full tree structure | -| Action | Extracts path to **new session file** | Changes leaf in **same session** | -| Summary | Never | Optional (user prompted) | -| Events | `session_before_fork` / `session_start` (`reason: "fork"`) | `session_before_tree` / `session_tree` | - -Use `/clone` when you want a new session file containing the full current active branch without rewinding to an earlier user message. - -## Tree UI - -``` -├─ user: "Hello, can you help..." -│ └─ assistant: "Of course! I can..." -│ ├─ user: "Let's try approach A..." -│ │ └─ assistant: "For approach A..." -│ │ └─ [compaction: 12k tokens] -│ │ └─ user: "That worked..." ← active -│ └─ user: "Actually, approach B..." -│ └─ assistant: "For approach B..." -``` - -### Controls - -| Key | Action | -|-----|--------| -| ↑/↓ | Navigate (depth-first order) | -| ←/→ | Page up/down | -| Ctrl+←/Ctrl+→ or Alt+←/Alt+→ | Fold/unfold and jump between branch segments | -| Shift+L | Set or clear a label on the selected node | -| Shift+T | Toggle label timestamps | -| Enter | Select node | -| Escape/Ctrl+C | Cancel | -| Ctrl+U | Toggle: user messages only | -| Ctrl+O | Toggle: show all (including custom/label entries) | - -`Ctrl+←` or `Alt+←` folds the current node if it is foldable. Foldable nodes are roots and branch segment starts that have visible children. If the current node is not foldable, or is already folded, the selection jumps up to the previous visible branch segment start. - -`Ctrl+→` or `Alt+→` unfolds the current node if it is folded. Otherwise, the selection jumps down to the next visible branch segment start, or to the branch end when there is no further branch point. - -### Display - -- Height: half terminal height -- Current leaf marked with `← active` -- Labels shown inline: `[label-name]` -- `Shift+T` shows the latest label-change timestamp next to labeled nodes -- Foldable branch starts show `⊟` in the connector. Folded branches show `⊞` -- Active path marker `•` appears after the fold indicator when applicable -- Search and filter changes reset all folds -- Default filter hides `label` and `custom` entries (shown in Ctrl+O mode) -- At each branch point, the active subtree is shown first; other sibling branches are sorted by timestamp (oldest first) - -## Selection Behavior - -### User Message or Custom Message -1. Leaf set to **parent** of selected node (or `null` if root) -2. Message text placed in **editor** for re-submission -3. User edits and submits, creating a new branch - -### Non-User Message (assistant, compaction, etc.) -1. Leaf set to **selected node** -2. Editor stays empty -3. User continues from that point - -### Selecting Root User Message -If user selects the very first message (has no parent): -1. Leaf reset to `null` (empty conversation) -2. Message text placed in editor -3. User effectively restarts from scratch - -## Branch Summarization - -When switching branches, user is presented with three options: - -1. **No summary** - Switch immediately without summarizing -2. **Summarize** - Generate a summary using the default prompt -3. **Summarize with custom prompt** - Opens an editor to enter additional focus instructions that are appended to the default summarization prompt - -### What Gets Summarized - -Path from old leaf back to common ancestor with target: - -``` -A → B → C → D → E → F ← old leaf - ↘ G → H ← target -``` - -Abandoned path: D → E → F (summarized) - -Summarization stops at: -1. Common ancestor (always) -2. Compaction node (if encountered first) - -### Summary Storage - -Stored as `BranchSummaryEntry`: - -```typescript -interface BranchSummaryEntry { - type: "branch_summary"; - id: string; - parentId: string; // New leaf position - timestamp: string; - fromId: string; // Old leaf we abandoned - summary: string; // LLM-generated summary - details?: unknown; // Optional hook data -} -``` - -## Implementation - -### AgentSession.navigateTree() - -```typescript -async navigateTree( - targetId: string, - options?: { - summarize?: boolean; - customInstructions?: string; - replaceInstructions?: boolean; - label?: string; - } -): Promise<{ editorText?: string; cancelled: boolean }> -``` - -Options: -- `summarize`: Whether to generate a summary of the abandoned branch -- `customInstructions`: Custom instructions for the summarizer -- `replaceInstructions`: If true, `customInstructions` replaces the default prompt instead of being appended -- `label`: Label to attach to the branch summary entry (or target entry if not summarizing) - -Flow: -1. Validate target, check no-op (target === current leaf) -2. Find common ancestor between old leaf and target -3. Collect entries to summarize (if requested) -4. Fire `session_before_tree` event (hook can cancel or provide summary) -5. Run default summarizer if needed -6. Switch leaf via `branch()` or `branchWithSummary()` -7. Update agent: `agent.state.messages = sessionManager.buildSessionContext().messages` -8. Fire `session_tree` event -9. Notify custom tools via session event -10. Return result with `editorText` if user message was selected - -### SessionManager - -- `getLeafUuid(): string | null` - Current leaf (null if empty) -- `resetLeaf(): void` - Set leaf to null (for root user message navigation) -- `getTree(): SessionTreeNode[]` - Full tree with children sorted by timestamp -- `branch(id)` - Change leaf pointer -- `branchWithSummary(id, summary)` - Change leaf and create summary entry - -### InteractiveMode - -`/tree` command shows `TreeSelectorComponent`, then: -1. Prompt for summarization -2. Call `session.navigateTree()` -3. Clear and re-render chat -4. Set editor text if applicable - -## Hook Events - -### `session_before_tree` - -```typescript -interface TreePreparation { - targetId: string; - oldLeafId: string | null; - commonAncestorId: string | null; - entriesToSummarize: SessionEntry[]; - userWantsSummary: boolean; - customInstructions?: string; - replaceInstructions?: boolean; - label?: string; -} - -interface SessionBeforeTreeEvent { - type: "session_before_tree"; - preparation: TreePreparation; - signal: AbortSignal; -} - -interface SessionBeforeTreeResult { - cancel?: boolean; - summary?: { summary: string; details?: unknown }; - customInstructions?: string; // Override custom instructions - replaceInstructions?: boolean; // Override replace mode - label?: string; // Override label -} -``` - -Extensions can override `customInstructions`, `replaceInstructions`, and `label` by returning them from the `session_before_tree` handler. - -### `session_tree` - -```typescript -interface SessionTreeEvent { - type: "session_tree"; - newLeafId: string | null; - oldLeafId: string | null; - summaryEntry?: BranchSummaryEntry; - fromHook?: boolean; -} -``` - -### Example: Custom Summarizer - -```typescript -export default function(pi: HookAPI) { - pi.on("session_before_tree", async (event, ctx) => { - if (!event.preparation.userWantsSummary) return; - if (event.preparation.entriesToSummarize.length === 0) return; - - const summary = await myCustomSummarizer(event.preparation.entriesToSummarize); - return { summary: { summary, details: { custom: true } } }; - }); -} -``` - -## Error Handling - -- Summarization failure: cancels navigation, shows error -- User abort (Escape): cancels navigation -- Hook returns `cancel: true`: cancels navigation silently diff --git a/packages/coding-agent/docs/usage.md b/packages/coding-agent/docs/usage.md index 12084676..1b43783d 100644 --- a/packages/coding-agent/docs/usage.md +++ b/packages/coding-agent/docs/usage.md @@ -88,7 +88,7 @@ Useful session commands: - `/clone` duplicates the current active branch into a new session file. - `/compact` summarizes older messages to free context. -See [Sessions](session.md), [Session Tree](tree.md), and [Compaction](compaction.md) for details. +See [Sessions](sessions.md) and [Compaction](compaction.md) for details. ## Context Files