docs(coding-agent): improve README structure and update session/compaction docs

- README-NEW.md: add Quick Start, Interactive Mode, Sessions sections
- session.md: add Message Types section, complete SessionManager API, fix source links to GitHub URLs
- compaction.md: rename hooks to extensions, fix source links to GitHub URLs
- keybindings.md: new file documenting all keyboard shortcuts
This commit is contained in:
Mario Zechner 2026-01-26 01:25:15 +01:00
parent 859a4e05b6
commit 28ab25b07e
4 changed files with 412 additions and 64 deletions

View file

@ -2,12 +2,14 @@
LLMs have limited context windows. When conversations grow too long, pi uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
**Source files:**
- [`src/core/compaction/compaction.ts`](../src/core/compaction/compaction.ts) - Auto-compaction logic
- [`src/core/compaction/branch-summarization.ts`](../src/core/compaction/branch-summarization.ts) - Branch summarization
- [`src/core/compaction/utils.ts`](../src/core/compaction/utils.ts) - Shared utilities (file tracking, serialization)
- [`src/core/session-manager.ts`](../src/core/session-manager.ts) - Entry types (`CompactionEntry`, `BranchSummaryEntry`)
- [`src/core/hooks/types.ts`](../src/core/hooks/types.ts) - Hook event types
**Source files** ([pi-mono](https://github.com/badlogic/pi-mono)):
- [`packages/coding-agent/src/core/compaction/compaction.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) - Auto-compaction logic
- [`packages/coding-agent/src/core/compaction/branch-summarization.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) - Branch summarization
- [`packages/coding-agent/src/core/compaction/utils.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/utils.ts) - Shared utilities (file tracking, serialization)
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts) - Entry types (`CompactionEntry`, `BranchSummaryEntry`)
- [`packages/coding-agent/src/core/extensions/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/extensions/types.ts) - Extension event types
For TypeScript definitions in your project, inspect `node_modules/@mariozechner/pi-coding-agent/dist/`.
## Overview
@ -108,13 +110,13 @@ Valid cut points are:
- User messages
- Assistant messages
- BashExecution messages
- Hook messages (custom_message, branch_summary)
- Custom messages (custom_message, branch_summary)
Never cut at tool results (they must stay with their tool call).
### CompactionEntry Structure
Defined in [`src/core/session-manager.ts`](../src/core/session-manager.ts):
Defined in [`session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts):
```typescript
interface CompactionEntry<T = unknown> {
@ -125,8 +127,8 @@ interface CompactionEntry<T = unknown> {
summary: string;
firstKeptEntryId: string;
tokensBefore: number;
fromHook?: boolean; // true if hook provided the compaction
details?: T; // hook-specific data
fromHook?: boolean; // true if provided by extension (legacy field name)
details?: T; // implementation-specific data
}
// Default compaction uses this for details (from compaction.ts):
@ -136,9 +138,9 @@ interface CompactionDetails {
}
```
Hooks can store any JSON-serializable data in `details`. The default compaction tracks file operations, but custom compaction hooks can use their own structure.
Extensions can store any JSON-serializable data in `details`. The default compaction tracks file operations, but custom extension implementations can use their own structure.
See [`prepareCompaction()`](../src/core/compaction/compaction.ts) and [`compact()`](../src/core/compaction/compaction.ts) for the implementation.
See [`prepareCompaction()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) and [`compact()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) for the implementation.
## Branch Summarization
@ -181,7 +183,7 @@ This means file tracking accumulates across multiple compactions or nested branc
### BranchSummaryEntry Structure
Defined in [`src/core/session-manager.ts`](../src/core/session-manager.ts):
Defined in [`session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts):
```typescript
interface BranchSummaryEntry<T = unknown> {
@ -191,8 +193,8 @@ interface BranchSummaryEntry<T = unknown> {
timestamp: number;
summary: string;
fromId: string; // Entry we navigated from
fromHook?: boolean; // true if hook provided the summary
details?: T; // hook-specific data
fromHook?: boolean; // true if provided by extension (legacy field name)
details?: T; // implementation-specific data
}
// Default branch summarization uses this for details (from branch-summarization.ts):
@ -202,9 +204,9 @@ interface BranchSummaryDetails {
}
```
Same as compaction, hooks can store custom data in `details`.
Same as compaction, extensions can store custom data in `details`.
See [`collectEntriesForBranchSummary()`](../src/core/compaction/branch-summarization.ts), [`prepareBranchEntries()`](../src/core/compaction/branch-summarization.ts), and [`generateBranchSummary()`](../src/core/compaction/branch-summarization.ts) for the implementation.
See [`collectEntriesForBranchSummary()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), [`prepareBranchEntries()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), and [`generateBranchSummary()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) for the implementation.
## Summary Format
@ -248,7 +250,7 @@ path/to/changed.ts
### Message Serialization
Before summarization, messages are serialized to text via [`serializeConversation()`](../src/core/compaction/utils.ts):
Before summarization, messages are serialized to text via [`serializeConversation()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/utils.ts):
```
[User]: What they said
@ -260,9 +262,9 @@ Before summarization, messages are serialized to text via [`serializeConversatio
This prevents the model from treating it as a conversation to continue.
## Custom Summarization via Hooks
## Custom Summarization via Extensions
Hooks can intercept and customize both compaction and branch summarization. See [`src/core/hooks/types.ts`](../src/core/hooks/types.ts) for event type definitions.
Extensions can intercept and customize both compaction and branch summarization. See [`extensions/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/extensions/types.ts) for event type definitions.
### session_before_compact
@ -332,7 +334,7 @@ pi.on("session_before_compact", async (event, ctx) => {
});
```
See [examples/hooks/custom-compaction.ts](../examples/hooks/custom-compaction.ts) for a complete example using a different model.
See [custom-compaction.ts](../examples/extensions/custom-compaction.ts) for a complete example using a different model.
### session_before_tree

View file

@ -0,0 +1,162 @@
# Keybindings
All keyboard shortcuts can be customized via `~/.pi/agent/keybindings.json`. Each action can be bound to one or more keys.
## Key Format
`modifier+key` where modifiers are `ctrl`, `shift`, `alt` (combinable) and keys are:
- **Letters:** `a-z`
- **Special:** `escape`, `esc`, `enter`, `return`, `tab`, `space`, `backspace`, `delete`, `insert`, `clear`, `home`, `end`, `pageUp`, `pageDown`, `up`, `down`, `left`, `right`
- **Function:** `f1`-`f12`
- **Symbols:** `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, etc.
## All Actions
### Cursor Movement
| Action | Default | Description |
|--------|---------|-------------|
| `cursorUp` | `up` | Move cursor up |
| `cursorDown` | `down` | Move cursor down |
| `cursorLeft` | `left` | Move cursor left |
| `cursorRight` | `right` | Move cursor right |
| `cursorWordLeft` | `alt+left`, `ctrl+left` | Move cursor word left |
| `cursorWordRight` | `alt+right`, `ctrl+right` | Move cursor word right |
| `cursorLineStart` | `home`, `ctrl+a` | Move to line start |
| `cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
| `pageUp` | `pageUp` | Scroll up by page |
| `pageDown` | `pageDown` | Scroll down by page |
### Deletion
| Action | Default | Description |
|--------|---------|-------------|
| `deleteCharBackward` | `backspace` | Delete character backward |
| `deleteCharForward` | `delete` | Delete character forward |
| `deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward |
| `deleteWordForward` | `alt+d`, `alt+delete` | Delete word forward |
| `deleteToLineStart` | `ctrl+u` | Delete to line start |
| `deleteToLineEnd` | `ctrl+k` | Delete to line end |
### Text Input
| Action | Default | Description |
|--------|---------|-------------|
| `newLine` | `shift+enter` | Insert new line |
| `submit` | `enter` | Submit input |
| `tab` | `tab` | Tab / autocomplete |
### Kill Ring
| Action | Default | Description |
|--------|---------|-------------|
| `yank` | `ctrl+y` | Paste most recently deleted text |
| `yankPop` | `alt+y` | Cycle through deleted text after yank |
| `undo` | `ctrl+-` | Undo last edit |
### Clipboard
| Action | Default | Description |
|--------|---------|-------------|
| `copy` | `ctrl+c` | Copy selection |
| `pasteImage` | `ctrl+v` | Paste image from clipboard |
### Application
| Action | Default | Description |
|--------|---------|-------------|
| `interrupt` | `escape` | Cancel / abort |
| `clear` | `ctrl+c` | Clear editor |
| `exit` | `ctrl+d` | Exit (when editor empty) |
| `suspend` | `ctrl+z` | Suspend to background |
| `externalEditor` | `ctrl+g` | Open in external editor (`$VISUAL` or `$EDITOR`) |
### Models & Thinking
| Action | Default | Description |
|--------|---------|-------------|
| `selectModel` | `ctrl+l` | Open model selector |
| `cycleModelForward` | `ctrl+p` | Cycle to next model |
| `cycleModelBackward` | `shift+ctrl+p` | Cycle to previous model |
| `cycleThinkingLevel` | `shift+tab` | Cycle thinking level |
### Display
| Action | Default | Description |
|--------|---------|-------------|
| `expandTools` | `ctrl+o` | Collapse/expand tool output |
| `toggleThinking` | `ctrl+t` | Collapse/expand thinking blocks |
### Message Queue
| Action | Default | Description |
|--------|---------|-------------|
| `followUp` | `alt+enter` | Queue follow-up message |
| `dequeue` | `alt+up` | Restore queued messages to editor |
### Selection (Lists, Pickers)
| Action | Default | Description |
|--------|---------|-------------|
| `selectUp` | `up` | Move selection up |
| `selectDown` | `down` | Move selection down |
| `selectPageUp` | `pageUp` | Page up in list |
| `selectPageDown` | `pageDown` | Page down in list |
| `selectConfirm` | `enter` | Confirm selection |
| `selectCancel` | `escape`, `ctrl+c` | Cancel selection |
### Session Picker
| Action | Default | Description |
|--------|---------|-------------|
| `toggleSessionPath` | `ctrl+p` | Toggle path display |
| `toggleSessionSort` | `ctrl+s` | Toggle sort mode |
| `renameSession` | `ctrl+r` | Rename session |
| `deleteSession` | `ctrl+d` | Delete session |
| `deleteSessionNoninvasive` | `ctrl+backspace` | Delete session (when query empty) |
## Custom Configuration
Create `~/.pi/agent/keybindings.json`:
```json
{
"cursorUp": ["up", "ctrl+p"],
"cursorDown": ["down", "ctrl+n"],
"deleteWordBackward": ["ctrl+w", "alt+backspace"]
}
```
Each action can have a single key or an array of keys. User config overrides defaults.
### Emacs Example
```json
{
"cursorUp": ["up", "ctrl+p"],
"cursorDown": ["down", "ctrl+n"],
"cursorLeft": ["left", "ctrl+b"],
"cursorRight": ["right", "ctrl+f"],
"cursorWordLeft": ["alt+left", "alt+b"],
"cursorWordRight": ["alt+right", "alt+f"],
"deleteCharForward": ["delete", "ctrl+d"],
"deleteCharBackward": ["backspace", "ctrl+h"],
"newLine": ["shift+enter", "ctrl+j"]
}
```
### Vim Example
```json
{
"cursorUp": ["up", "alt+k"],
"cursorDown": ["down", "alt+j"],
"cursorLeft": ["left", "alt+h"],
"cursorRight": ["right", "alt+l"],
"cursorWordLeft": ["alt+left", "alt+b"],
"cursorWordRight": ["alt+right", "alt+w"]
}
```

View file

@ -26,11 +26,147 @@ Sessions have a version field in the header:
Existing sessions are automatically migrated to the current version (v3) when loaded.
## Type Definitions
## Source Files
- [`src/core/session-manager.ts`](../src/core/session-manager.ts) - Session entry types
- [`packages/agent-core/src/types.ts`](../../agent-core/src/types.ts) - `AgentMessage`
- [`packages/ai/src/types.ts`](../../ai/src/types.ts) - `UserMessage`, `AssistantMessage`, `ToolResultMessage`, `Usage`, `ToolCall`, `ImageContent`, `TextContent`
Source on GitHub ([pi-mono](https://github.com/badlogic/pi-mono)):
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts) - Session entry types and SessionManager
- [`packages/coding-agent/src/core/messages.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts) - Extended message types (BashExecutionMessage, CustomMessage, etc.)
- [`packages/ai/src/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/types.ts) - Base message types (UserMessage, AssistantMessage, ToolResultMessage)
- [`packages/agent/src/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/agent/src/types.ts) - AgentMessage union type
For TypeScript definitions in your project, inspect `node_modules/@mariozechner/pi-coding-agent/dist/` and `node_modules/@mariozechner/pi-ai/dist/`.
## Message Types
Session entries contain `AgentMessage` objects. Understanding these types is essential for parsing sessions and writing extensions.
### Content Blocks
Messages contain arrays of typed content blocks:
```typescript
interface TextContent {
type: "text";
text: string;
}
interface ImageContent {
type: "image";
data: string; // base64 encoded
mimeType: string; // e.g., "image/jpeg", "image/png"
}
interface ThinkingContent {
type: "thinking";
thinking: string;
}
interface ToolCall {
type: "toolCall";
id: string;
name: string;
arguments: Record<string, any>;
}
```
### Base Message Types (from pi-ai)
```typescript
interface UserMessage {
role: "user";
content: string | (TextContent | ImageContent)[];
timestamp: number; // Unix ms
}
interface AssistantMessage {
role: "assistant";
content: (TextContent | ThinkingContent | ToolCall)[];
api: string;
provider: string;
model: string;
usage: Usage;
stopReason: "stop" | "length" | "toolUse" | "error" | "aborted";
errorMessage?: string;
timestamp: number;
}
interface ToolResultMessage {
role: "toolResult";
toolCallId: string;
toolName: string;
content: (TextContent | ImageContent)[];
details?: any; // Tool-specific metadata
isError: boolean;
timestamp: number;
}
interface Usage {
input: number;
output: number;
cacheRead: number;
cacheWrite: number;
totalTokens: number;
cost: {
input: number;
output: number;
cacheRead: number;
cacheWrite: number;
total: number;
};
}
```
### Extended Message Types (from pi-coding-agent)
```typescript
interface BashExecutionMessage {
role: "bashExecution";
command: string;
output: string;
exitCode: number | undefined;
cancelled: boolean;
truncated: boolean;
fullOutputPath?: string;
excludeFromContext?: boolean; // true for !! prefix commands
timestamp: number;
}
interface CustomMessage {
role: "custom";
customType: string; // Extension identifier
content: string | (TextContent | ImageContent)[];
display: boolean; // Show in TUI
details?: any; // Extension-specific metadata
timestamp: number;
}
interface BranchSummaryMessage {
role: "branchSummary";
summary: string;
fromId: string; // Entry we branched from
timestamp: number;
}
interface CompactionSummaryMessage {
role: "compactionSummary";
summary: string;
tokensBefore: number;
timestamp: number;
}
```
### AgentMessage Union
```typescript
type AgentMessage =
| UserMessage
| AssistantMessage
| ToolResultMessage
| BashExecutionMessage
| CustomMessage
| BranchSummaryMessage
| CompactionSummaryMessage;
```
## Entry Base
@ -96,8 +232,8 @@ Created when context is compacted. Stores a summary of earlier messages.
```
Optional fields:
- `details`: Compaction-implementation specific data (e.g., file operations for default implementation, or custom data for extension implementations)
- `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated
- `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
- `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
### BranchSummaryEntry
@ -108,8 +244,8 @@ Created when switching branches via `/tree` with an LLM generated summary of the
```
Optional fields:
- `details`: File tracking data (`{ readFiles: string[], modifiedFiles: string[] }`) for default implementation, arbitrary for custom implementation
- `fromHook`: `true` if generated by an extension
- `details`: File tracking data (`{ readFiles: string[], modifiedFiles: string[] }`) for default, or custom data for extensions
- `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
### CustomEntry
@ -224,15 +360,25 @@ for (const line of lines) {
## SessionManager API
Key methods for working with sessions programmatically:
Key methods for working with sessions programmatically.
### Creation
### Static Creation Methods
- `SessionManager.create(cwd, sessionDir?)` - New session
- `SessionManager.open(path, sessionDir?)` - Open existing
- `SessionManager.open(path, sessionDir?)` - Open existing session file
- `SessionManager.continueRecent(cwd, sessionDir?)` - Continue most recent or create new
- `SessionManager.inMemory(cwd?)` - No file persistence
- `SessionManager.forkFrom(sourcePath, targetCwd, sessionDir?)` - Fork session from another project
### Appending (all return entry ID)
### Static Listing Methods
- `SessionManager.list(cwd, sessionDir?, onProgress?)` - List sessions for a directory
- `SessionManager.listAll(onProgress?)` - List all sessions across all projects
### Instance Methods - Session Management
- `newSession(options?)` - Start a new session (options: `{ parentSession?: string }`)
- `setSessionFile(path)` - Switch to a different session file
- `createBranchedSession(leafId)` - Extract branch to new session file
### Instance Methods - Appending (all return entry ID)
- `appendMessage(message)` - Add message
- `appendThinkingLevelChange(level)` - Record thinking change
- `appendModelChange(provider, modelId)` - Record model change
@ -242,7 +388,7 @@ Key methods for working with sessions programmatically:
- `appendCustomMessageEntry(customType, content, display, details?)` - Extension message (in context)
- `appendLabelChange(targetId, label)` - Set/clear label
### Tree Navigation
### Instance Methods - Tree Navigation
- `getLeafId()` - Current position
- `getLeafEntry()` - Get current leaf entry
- `getEntry(id)` - Get entry by ID
@ -254,8 +400,13 @@ Key methods for working with sessions programmatically:
- `resetLeaf()` - Reset leaf to null (before any entries)
- `branchWithSummary(entryId, summary, details?, fromHook?)` - Branch with context summary
### Context
- `buildSessionContext()` - Get messages for LLM
### Instance Methods - Context & Info
- `buildSessionContext()` - Get messages, thinkingLevel, and model for LLM
- `getEntries()` - All entries (excluding header)
- `getHeader()` - Session metadata
- `getHeader()` - Session header metadata
- `getSessionName()` - Get display name from latest session_info entry
- `getCwd()` - Working directory
- `getSessionDir()` - Session storage directory
- `getSessionId()` - Session UUID
- `getSessionFile()` - Session file path (undefined for in-memory)
- `isPersisted()` - Whether session is saved to disk