The interface from top to bottom:
@@ -134,7 +146,7 @@ Type `/` in the editor to trigger commands. [Extensions](#extensions) can regist
| `/copy` | Copy last assistant message to clipboard |
| `/export [file]` | Export session to HTML file |
| `/share` | Upload as private GitHub gist with shareable HTML link |
-| `/reload` | Reload extensions, skills, prompts, themes |
+| `/reload` | Reload extensions, skills, prompts, context files (themes hot-reload automatically) |
| `/hotkeys` | Show all keyboard shortcuts |
| `/changelog` | Display version history |
| `/quit`, `/exit` | Quit pi |
@@ -157,11 +169,22 @@ See `/hotkeys` for the full list. Customize via `~/.pi/agent/keybindings.json`.
| Ctrl+O | Collapse/expand tool output |
| Ctrl+T | Collapse/expand thinking blocks |
+### Message Queue
+
+Submit messages while the agent is working:
+
+- **Enter** queues a *steering* message, delivered after current tool execution (interrupts remaining tools)
+- **Alt+Enter** queues a *follow-up* message, delivered only after the agent finishes all work
+- **Escape** aborts and restores queued messages to editor
+- **Alt+Up** retrieves queued messages back to editor
+
+Configure delivery in [settings](docs/settings.md): `steeringMode` and `followUpMode` can be `"one-at-a-time"` (default, waits for response) or `"all"` (delivers all queued at once).
+
---
## 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.
+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.
### Management
@@ -178,6 +201,8 @@ pi --session # Use specific session file or ID
**`/tree`** - Navigate the session tree in-place. Select any previous point, continue from there, and switch between branches. All history preserved in a single file.
+
+
- Search by typing, page with ←/→
- Filter modes (Ctrl+O): default → no-tools → user-only → labeled-only → all
- Press `l` to label entries as bookmarks
@@ -192,71 +217,73 @@ Long sessions can exhaust context windows. Compaction summarizes older messages
**Automatic:** Enabled by default. Triggers on context overflow (recovers and retries) or when approaching the limit (proactive). Configure via `/settings` or `settings.json`.
-Compaction is lossy. The full history remains in the JSONL file; use `/tree` to revisit. Customize compaction behavior via [extensions](#extensions).
-
-See [docs/session.md](docs/session.md) for file format and [docs/compaction.md](docs/compaction.md) for internals.
+Compaction is lossy. The full history remains in the JSONL file; use `/tree` to revisit. Customize compaction behavior via [extensions](#extensions). See [docs/compaction.md](docs/compaction.md) for internals.
---
-## Configuration
+## Settings
-### Context Files
+Use `/settings` to modify common options, or edit JSON files directly:
-Pi loads `AGENTS.md` files at startup (global `~/.pi/agent/AGENTS.md`, parent directories, current directory). Use for project instructions, conventions, common commands.
-
-### System Prompt
-
-Replace the default system prompt with `.pi/SYSTEM.md` (project) or `~/.pi/agent/SYSTEM.md` (global). Append without replacing via `APPEND_SYSTEM.md`.
-
-### Custom Models
-
-Add Ollama, vLLM, LM Studio, or proxy endpoints via `~/.pi/agent/models.json`:
-
-```json
-{
- "providers": {
- "ollama": {
- "baseUrl": "http://localhost:11434/v1",
- "api": "openai-completions",
- "models": [{ "id": "llama-3.1-8b", "name": "Llama 3.1 8B", ... }]
- }
- }
-}
-```
-
-See [docs/models.md](docs/models.md) for full schema and examples.
-
-### Settings
-
-Global settings in `~/.pi/agent/settings.json`, project overrides in `.pi/settings.json`.
+| Location | Scope |
+|----------|-------|
+| `~/.pi/agent/settings.json` | Global (all projects) |
+| `.pi/settings.json` | Project (overrides global) |
See [docs/settings.md](docs/settings.md) for all options.
---
+## Context Files
+
+Pi loads `AGENTS.md` (or `CLAUDE.md`) at startup from:
+- `~/.pi/agent/AGENTS.md` (global)
+- Parent directories (walking up from cwd)
+- Current directory
+
+Use for project instructions, conventions, common commands. All matching files are concatenated.
+
+### System Prompt
+
+Replace the default system prompt with `.pi/SYSTEM.md` (project) or `~/.pi/agent/SYSTEM.md` (global). Append without replacing via `APPEND_SYSTEM.md`.
+
+---
+
## Customization
-### Themes
-
-Built-in: `dark`, `light`. Create custom themes in `~/.pi/agent/themes/*.json` with live reload.
-
-See [docs/themes.md](docs/themes.md).
-
### Prompt Templates
-Reusable prompts as Markdown files in `~/.pi/agent/prompts/` or `.pi/prompts/`. Type `/name` to expand.
+Reusable prompts as Markdown files. Type `/name` to expand.
-See [docs/prompt-templates.md](docs/prompt-templates.md).
+```markdown
+
+Review this code for bugs, security issues, and performance problems.
+Focus on: {{focus}}
+```
+
+Place in `~/.pi/agent/prompts/`, `.pi/prompts/`, or a [pi package](#pi-packages) to share with others. See [docs/prompt-templates.md](docs/prompt-templates.md).
### Skills
-On-demand capability packages following the [Agent Skills standard](https://agentskills.io). Place in `~/.pi/agent/skills/` or `.pi/skills/`. Invoke via `/skill:name` or let the agent load them automatically.
+On-demand capability packages following the [Agent Skills standard](https://agentskills.io). Invoke via `/skill:name` or let the agent load them automatically.
-See [docs/skills.md](docs/skills.md).
+```markdown
+
+# My Skill
+Use this skill when the user asks about X.
+
+## Steps
+1. Do this
+2. Then that
+```
+
+Place in `~/.pi/agent/skills/`, `.pi/skills/`, or a [pi package](#pi-packages) to share with others. See [docs/skills.md](docs/skills.md).
### Extensions
-TypeScript modules for custom tools, commands, event interception, and UI.
+
+
+TypeScript modules that extend pi with custom tools, commands, keyboard shortcuts, event handlers, and UI components.
```typescript
export default function (pi: ExtensionAPI) {
@@ -266,62 +293,67 @@ export default function (pi: ExtensionAPI) {
}
```
-Place in `~/.pi/agent/extensions/` or `.pi/extensions/`.
+**What's possible:**
+- Custom tools (or replace built-in tools entirely)
+- Sub-agents and plan mode
+- Custom compaction and summarization
+- Permission gates and path protection
+- Custom editors and UI components
+- Status lines, headers, footers
+- Git checkpointing and auto-commit
+- SSH and sandbox execution
+- MCP server integration
+- Make pi look like Claude Code
+- Games while waiting (yes, Doom runs)
+- ...anything you can dream up
-See [docs/extensions.md](docs/extensions.md) and [examples/extensions/](examples/extensions/).
+Place in `~/.pi/agent/extensions/`, `.pi/extensions/`, or a [pi package](#pi-packages) to share with others. See [docs/extensions.md](docs/extensions.md) and [examples/extensions/](examples/extensions/).
+
+### Themes
+
+Built-in: `dark`, `light`. Themes hot-reload: modify the active theme file and pi immediately applies changes.
+
+Place in `~/.pi/agent/themes/`, `.pi/themes/`, or a [pi package](#pi-packages) to share with others. See [docs/themes.md](docs/themes.md).
### Pi Packages
-Bundle and share extensions, skills, prompts, and themes via npm or git:
+Bundle and share extensions, skills, prompts, and themes via npm or git.
```bash
pi install npm:@foo/pi-tools
+pi install npm:@foo/pi-tools@1.2.3 # pinned version
pi install git:github.com/user/repo
+pi install git:github.com/user/repo@v1 # tag or commit
+pi install https://github.com/user/repo
+pi remove npm:@foo/pi-tools
pi list
-pi update
+pi update # skips pinned packages
+pi config # enable/disable extensions, skills, prompts, themes
```
+Packages install to `~/.pi/agent/git/` (git) or global npm. Use `-l` for project-local installs (`.pi/git/`, `.pi/npm/`).
+
+Create a package by adding a `pi` key to `package.json`:
+
+```json
+{
+ "name": "my-pi-package",
+ "keywords": ["pi-package"],
+ "pi": {
+ "extensions": ["./extensions"],
+ "skills": ["./skills"],
+ "prompts": ["./prompts"],
+ "themes": ["./themes"]
+ }
+}
+```
+
+Without a `pi` manifest, pi auto-discovers from conventional directories (`extensions/`, `skills/`, `prompts/`, `themes/`).
+
See [docs/packages.md](docs/packages.md).
---
-## CLI Reference
-
-```bash
-pi [options] [@files...] [messages...]
-```
-
-### Modes
-
-| Flag | Description |
-|------|-------------|
-| (default) | Interactive mode |
-| `-p`, `--print` | Print response and exit |
-| `--mode json` | JSON event stream |
-| `--mode rpc` | RPC mode for process integration |
-
-### Common Options
-
-| Option | Description |
-|--------|-------------|
-| `--provider`, `--model` | Select provider and model |
-| `--thinking ` | `off`, `minimal`, `low`, `medium`, `high` |
-| `--models ` | Patterns for Ctrl+P cycling |
-| `-c`, `--continue` | Continue most recent session |
-| `-r`, `--resume` | Browse and select session |
-| `--tools ` | Limit tools (default: `read,bash,edit,write`) |
-
-### File Arguments
-
-```bash
-pi @prompt.md "Answer this"
-pi @screenshot.png "What's in this image?"
-```
-
-See `pi --help` for all options.
-
----
-
## Programmatic Usage
### SDK
@@ -342,37 +374,162 @@ See [docs/sdk.md](docs/sdk.md) and [examples/sdk/](examples/sdk/).
### RPC Mode
+For non-Node.js integrations, use RPC mode over stdin/stdout:
+
```bash
-pi --mode rpc --no-session
+pi --mode rpc
```
See [docs/rpc.md](docs/rpc.md) for the protocol.
-### HTML Export
-
-```bash
-pi --export session.jsonl output.html
-```
-
---
## Philosophy
-**No MCP.** Build CLI tools with READMEs (see [Skills](#skills)). [Why?](https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/)
+Pi is aggressively extensible so it doesn't have to dictate your workflow. Features that other tools bake in can be built with [extensions](#extensions), [skills](#skills), or installed from third-party [pi packages](#pi-packages). This keeps the core minimal while letting you shape pi to fit how you work.
-**No sub-agents.** Spawn pi instances via tmux, or build your own with [Extensions](#extensions).
+**No MCP.** Build CLI tools with READMEs (see [Skills](#skills)), or build an extension that adds MCP support. [Why?](https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/)
-**No permission popups.** Run in a container or build your own confirmation flow.
+**No sub-agents.** There's many ways to do this. Spawn pi instances via tmux, or build your own with [extensions](#extensions), or install a package that does it your way.
-**No plan mode.** Write plans to files, start fresh for implementation.
+**No permission popups.** Run in a container, or build your own confirmation flow with [extensions](#extensions) inline with your environment and security requirements.
+
+**No plan mode.** Write plans to files, or build it with [extensions](#extensions), or install a package.
+
+**No built-in to-dos.** They confuse models. Use a TODO.md file, or build your own with [extensions](#extensions).
+
+**No background bash.** Use tmux. Full observability, direct interaction.
Read the [blog post](https://mariozechner.at/posts/2025-11-30-pi-coding-agent/) for the full rationale.
---
-## Development
+## CLI Reference
-See [docs/development.md](docs/development.md) for forking, rebranding, and debugging.
+```bash
+pi [options] [@files...] [messages...]
+```
+
+### Package Commands
+
+```bash
+pi install [-l] # Install package, -l for project-local
+pi remove [-l] # Remove package
+pi update [source] # Update packages (skips pinned)
+pi list # List installed packages
+pi config # Enable/disable package resources
+```
+
+### Modes
+
+| Flag | Description |
+|------|-------------|
+| (default) | Interactive mode |
+| `-p`, `--print` | Print response and exit |
+| `--mode json` | Output all events as JSON lines (see [docs/json.md](docs/json.md)) |
+| `--mode rpc` | RPC mode for process integration (see [docs/rpc.md](docs/rpc.md)) |
+| `--export [out]` | Export session to HTML |
+
+### Model Options
+
+| Option | Description |
+|--------|-------------|
+| `--provider ` | Provider (anthropic, openai, google, etc.) |
+| `--model ` | Model ID |
+| `--api-key ` | API key (overrides env vars) |
+| `--thinking ` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` |
+| `--models ` | Comma-separated patterns for Ctrl+P cycling |
+| `--list-models [search]` | List available models |
+
+### Session Options
+
+| Option | Description |
+|--------|-------------|
+| `-c`, `--continue` | Continue most recent session |
+| `-r`, `--resume` | Browse and select session |
+| `--session ` | Use specific session file or partial UUID |
+| `--session-dir ` | Custom session storage directory |
+| `--no-session` | Ephemeral mode (don't save) |
+
+### Tool Options
+
+| Option | Description |
+|--------|-------------|
+| `--tools ` | Enable specific built-in tools (default: `read,bash,edit,write`) |
+| `--no-tools` | Disable all built-in tools (extension tools still work) |
+
+Available built-in tools: `read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`
+
+### Resource Options
+
+| Option | Description |
+|--------|-------------|
+| `-e`, `--extension ` | Load extension from path, npm, or git (repeatable) |
+| `--no-extensions` | Disable extension discovery |
+| `--skill ` | Load skill (repeatable) |
+| `--no-skills` | Disable skill discovery |
+| `--prompt-template ` | Load prompt template (repeatable) |
+| `--no-prompt-templates` | Disable prompt template discovery |
+| `--theme ` | Load theme (repeatable) |
+| `--no-themes` | Disable theme discovery |
+
+Combine `--no-*` with explicit flags to load exactly what you need, ignoring settings.json (e.g., `--no-extensions -e ./my-ext.ts`).
+
+### Other Options
+
+| Option | Description |
+|--------|-------------|
+| `--system-prompt ` | Replace default prompt (context files and skills still appended) |
+| `--append-system-prompt ` | Append to system prompt |
+| `--verbose` | Force verbose startup |
+| `-h`, `--help` | Show help |
+| `-v`, `--version` | Show version |
+
+### File Arguments
+
+Prefix files with `@` to include in the message:
+
+```bash
+pi @prompt.md "Answer this"
+pi -p @screenshot.png "What's in this image?"
+pi @code.ts @test.ts "Review these files"
+```
+
+### Examples
+
+```bash
+# Interactive with initial prompt
+pi "List all .ts files in src/"
+
+# Non-interactive
+pi -p "Summarize this codebase"
+
+# Different model
+pi --provider openai --model gpt-4o "Help me refactor"
+
+# Limit model cycling
+pi --models "claude-*,gpt-4o"
+
+# Read-only mode
+pi --tools read,grep,find,ls -p "Review the code"
+
+# High thinking level
+pi --thinking high "Solve this complex problem"
+```
+
+### Environment Variables
+
+| Variable | Description |
+|----------|-------------|
+| `PI_CODING_AGENT_DIR` | Override config directory (default: `~/.pi/agent`) |
+| `PI_SKIP_VERSION_CHECK` | Skip version check at startup |
+| `VISUAL`, `EDITOR` | External editor for Ctrl+G |
+
+---
+
+## Contributing & Development
+
+See [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines and [docs/development.md](docs/development.md) for setup, forking, and debugging.
---
diff --git a/packages/coding-agent/docs/development.md b/packages/coding-agent/docs/development.md
new file mode 100644
index 00000000..f0e6b6a0
--- /dev/null
+++ b/packages/coding-agent/docs/development.md
@@ -0,0 +1,69 @@
+# Development
+
+See [AGENTS.md](../../../AGENTS.md) for additional guidelines.
+
+## Setup
+
+```bash
+git clone https://github.com/badlogic/pi-mono
+cd pi-mono
+npm install
+npm run build
+```
+
+Run from source:
+
+```bash
+./pi-test.sh
+```
+
+## Forking / Rebranding
+
+Configure via `package.json`:
+
+```json
+{
+ "piConfig": {
+ "name": "pi",
+ "configDir": ".pi"
+ }
+}
+```
+
+Change `name`, `configDir`, and `bin` field for your fork. Affects CLI banner, config paths, and environment variable names.
+
+## Path Resolution
+
+Three execution modes: npm install, standalone binary, tsx from source.
+
+**Always use `src/config.ts`** for package assets:
+
+```typescript
+import { getPackageDir, getThemeDir } from "./config.js";
+```
+
+Never use `__dirname` directly for package assets.
+
+## Debug Command
+
+`/debug` (hidden) writes to `~/.pi/agent/pi-debug.log`:
+- Rendered TUI lines with ANSI codes
+- Last messages sent to the LLM
+
+## Testing
+
+```bash
+./test.sh # Run non-LLM tests (no API keys needed)
+npm test # Run all tests
+npm test -- test/specific.test.ts # Run specific test
+```
+
+## Project Structure
+
+```
+packages/
+ ai/ # LLM provider abstraction
+ agent/ # Agent loop and message types
+ tui/ # Terminal UI components
+ coding-agent/ # CLI and interactive mode
+```
diff --git a/packages/coding-agent/docs/images/doom-extension.png b/packages/coding-agent/docs/images/doom-extension.png
new file mode 100644
index 00000000..965acc93
Binary files /dev/null and b/packages/coding-agent/docs/images/doom-extension.png differ
diff --git a/packages/coding-agent/docs/images/tree-view.png b/packages/coding-agent/docs/images/tree-view.png
new file mode 100644
index 00000000..8ef603d9
Binary files /dev/null and b/packages/coding-agent/docs/images/tree-view.png differ
diff --git a/packages/coding-agent/docs/json.md b/packages/coding-agent/docs/json.md
new file mode 100644
index 00000000..e1a68a85
--- /dev/null
+++ b/packages/coding-agent/docs/json.md
@@ -0,0 +1,79 @@
+# JSON Event Stream Mode
+
+```bash
+pi --mode json "Your prompt"
+```
+
+Outputs all session events as JSON lines to stdout. Useful for integrating pi into other tools or custom UIs.
+
+## Event Types
+
+Events are defined in [`AgentSessionEvent`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/agent-session.ts#L102):
+
+```typescript
+type AgentSessionEvent =
+ | AgentEvent
+ | { type: "auto_compaction_start"; reason: "threshold" | "overflow" }
+ | { type: "auto_compaction_end"; result: CompactionResult | undefined; aborted: boolean; willRetry: boolean; errorMessage?: string }
+ | { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
+ | { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string };
+```
+
+Base events from [`AgentEvent`](https://github.com/badlogic/pi-mono/blob/main/packages/agent/src/types.ts#L179):
+
+```typescript
+type AgentEvent =
+ // Agent lifecycle
+ | { type: "agent_start" }
+ | { type: "agent_end"; messages: AgentMessage[] }
+ // Turn lifecycle
+ | { type: "turn_start" }
+ | { type: "turn_end"; message: AgentMessage; toolResults: ToolResultMessage[] }
+ // Message lifecycle
+ | { type: "message_start"; message: AgentMessage }
+ | { type: "message_update"; message: AgentMessage; assistantMessageEvent: AssistantMessageEvent }
+ | { type: "message_end"; message: AgentMessage }
+ // Tool execution
+ | { type: "tool_execution_start"; toolCallId: string; toolName: string; args: any }
+ | { type: "tool_execution_update"; toolCallId: string; toolName: string; args: any; partialResult: any }
+ | { type: "tool_execution_end"; toolCallId: string; toolName: string; result: any; isError: boolean };
+```
+
+## Message Types
+
+Base messages from [`packages/ai/src/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/types.ts#L134):
+- `UserMessage` (line 134)
+- `AssistantMessage` (line 140)
+- `ToolResultMessage` (line 152)
+
+Extended messages from [`packages/coding-agent/src/core/messages.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts#L29):
+- `BashExecutionMessage` (line 29)
+- `CustomMessage` (line 46)
+- `BranchSummaryMessage` (line 55)
+- `CompactionSummaryMessage` (line 62)
+
+## Output Format
+
+Each line is a JSON object. The first line is the session header:
+
+```json
+{"type":"session","version":3,"id":"uuid","timestamp":"...","cwd":"/path"}
+```
+
+Followed by events as they occur:
+
+```json
+{"type":"agent_start"}
+{"type":"turn_start"}
+{"type":"message_start","message":{"role":"assistant","content":[],...}}
+{"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_delta","delta":"Hello",...}}
+{"type":"message_end","message":{...}}
+{"type":"turn_end","message":{...},"toolResults":[]}
+{"type":"agent_end","messages":[...]}
+```
+
+## Example
+
+```bash
+pi --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'
+```
diff --git a/packages/coding-agent/docs/settings.md b/packages/coding-agent/docs/settings.md
new file mode 100644
index 00000000..905524fe
--- /dev/null
+++ b/packages/coding-agent/docs/settings.md
@@ -0,0 +1,212 @@
+# Settings
+
+Pi uses JSON settings files with project settings overriding global settings.
+
+| Location | Scope |
+|----------|-------|
+| `~/.pi/agent/settings.json` | Global (all projects) |
+| `.pi/settings.json` | Project (current directory) |
+
+Edit directly or use `/settings` for common options.
+
+## All Settings
+
+### Model & Thinking
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `defaultProvider` | string | - | Default provider (e.g., `"anthropic"`, `"openai"`) |
+| `defaultModel` | string | - | Default model ID |
+| `defaultThinkingLevel` | string | - | `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"` |
+| `hideThinkingBlock` | boolean | `false` | Hide thinking blocks in output |
+| `thinkingBudgets` | object | - | Custom token budgets per thinking level |
+
+#### thinkingBudgets
+
+```json
+{
+ "thinkingBudgets": {
+ "minimal": 1024,
+ "low": 4096,
+ "medium": 10240,
+ "high": 32768
+ }
+}
+```
+
+### UI & Display
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `theme` | string | `"dark"` | Theme name (`"dark"`, `"light"`, or custom) |
+| `quietStartup` | boolean | `false` | Hide startup header |
+| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
+| `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"` or `"fork"` |
+| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
+| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
+
+### Compaction
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `compaction.enabled` | boolean | `true` | Enable auto-compaction |
+| `compaction.reserveTokens` | number | `16384` | Tokens reserved for LLM response |
+| `compaction.keepRecentTokens` | number | `20000` | Recent tokens to keep (not summarized) |
+
+```json
+{
+ "compaction": {
+ "enabled": true,
+ "reserveTokens": 16384,
+ "keepRecentTokens": 20000
+ }
+}
+```
+
+### Branch Summary
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `branchSummary.reserveTokens` | number | `16384` | Tokens reserved for branch summarization |
+
+### Retry
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `retry.enabled` | boolean | `true` | Enable automatic retry on transient errors |
+| `retry.maxRetries` | number | `3` | Maximum retry attempts |
+| `retry.baseDelayMs` | number | `2000` | Base delay for exponential backoff (2s, 4s, 8s) |
+
+```json
+{
+ "retry": {
+ "enabled": true,
+ "maxRetries": 3,
+ "baseDelayMs": 2000
+ }
+}
+```
+
+### Message Delivery
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `steeringMode` | string | `"one-at-a-time"` | How steering messages are sent: `"all"` or `"one-at-a-time"` |
+| `followUpMode` | string | `"one-at-a-time"` | How follow-up messages are sent: `"all"` or `"one-at-a-time"` |
+
+### Terminal & Images
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `terminal.showImages` | boolean | `true` | Show images in terminal (if supported) |
+| `images.autoResize` | boolean | `true` | Resize images to 2000x2000 max |
+| `images.blockImages` | boolean | `false` | Block all images from being sent to LLM |
+
+### Shell
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `shellPath` | string | - | Custom shell path (e.g., for Cygwin on Windows) |
+| `shellCommandPrefix` | string | - | Prefix for every bash command (e.g., `"shopt -s expand_aliases"`) |
+
+### Model Cycling
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `enabledModels` | string[] | - | Model patterns for Ctrl+P cycling (same format as `--models` CLI flag) |
+
+```json
+{
+ "enabledModels": ["claude-*", "gpt-4o", "gemini-2*"]
+}
+```
+
+### Markdown
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `markdown.codeBlockIndent` | string | `" "` | Indentation for code blocks |
+
+### Resources
+
+These settings define where to load extensions, skills, prompts, and themes from.
+
+| Setting | Type | Default | Description |
+|---------|------|---------|-------------|
+| `packages` | array | `[]` | npm/git packages to load resources from |
+| `extensions` | string[] | `[]` | Local extension file paths or directories |
+| `skills` | string[] | `[]` | Local skill file paths or directories |
+| `prompts` | string[] | `[]` | Local prompt template paths or directories |
+| `themes` | string[] | `[]` | Local theme file paths or directories |
+| `enableSkillCommands` | boolean | `true` | Register skills as `/skill:name` commands |
+
+#### packages
+
+String form loads all resources from a package:
+
+```json
+{
+ "packages": ["pi-skills", "@org/my-extension"]
+}
+```
+
+Object form filters which resources to load:
+
+```json
+{
+ "packages": [
+ {
+ "source": "pi-skills",
+ "skills": ["brave-search", "transcribe"],
+ "extensions": []
+ }
+ ]
+}
+```
+
+See [packages.md](packages.md) for package management details.
+
+## Example
+
+```json
+{
+ "defaultProvider": "anthropic",
+ "defaultModel": "claude-sonnet-4-20250514",
+ "defaultThinkingLevel": "medium",
+ "theme": "dark",
+ "compaction": {
+ "enabled": true,
+ "reserveTokens": 16384,
+ "keepRecentTokens": 20000
+ },
+ "retry": {
+ "enabled": true,
+ "maxRetries": 3
+ },
+ "enabledModels": ["claude-*", "gpt-4o"],
+ "packages": ["pi-skills"]
+}
+```
+
+## Project Overrides
+
+Project settings (`.pi/settings.json`) override global settings. Nested objects are merged:
+
+```json
+// ~/.pi/agent/settings.json (global)
+{
+ "theme": "dark",
+ "compaction": { "enabled": true, "reserveTokens": 16384 }
+}
+
+// .pi/settings.json (project)
+{
+ "compaction": { "reserveTokens": 8192 }
+}
+
+// Result
+{
+ "theme": "dark",
+ "compaction": { "enabled": true, "reserveTokens": 8192 }
+}
+```
diff --git a/packages/coding-agent/docs/tui.md b/packages/coding-agent/docs/tui.md
index c8ca032e..ba91b44d 100644
--- a/packages/coding-agent/docs/tui.md
+++ b/packages/coding-agent/docs/tui.md
@@ -2,7 +2,7 @@
# TUI Components
-Hooks and custom tools can render custom TUI components for interactive user interfaces. This page covers the component system and available building blocks.
+Extensions and custom tools can render custom TUI components for interactive user interfaces. This page covers the component system and available building blocks.
**Source:** [`@mariozechner/pi-tui`](https://github.com/badlogic/pi-mono/tree/main/packages/tui)
@@ -14,7 +14,8 @@ All components implement:
interface Component {
render(width: number): string[];
handleInput?(data: string): void;
- invalidate?(): void;
+ wantsKeyRelease?: boolean;
+ invalidate(): void;
}
```
@@ -22,7 +23,8 @@ interface Component {
|--------|-------------|
| `render(width)` | Return array of strings (one per line). Each line **must not exceed `width`**. |
| `handleInput?(data)` | Receive keyboard input when component has focus. |
-| `invalidate?()` | Clear cached render state. |
+| `wantsKeyRelease?` | If true, component receives key release events (Kitty protocol). Default: false. |
+| `invalidate()` | Clear cached render state. Called on theme changes. |
The TUI appends a full SGR reset and OSC 8 reset at the end of each rendered line. Styles do not carry across lines. If you emit multi-line text with styling, reapply styles per line or use `wrapTextWithAnsi()` so styles are preserved for each wrapped line.
@@ -84,7 +86,7 @@ Without this propagation, typing with an IME (Chinese, Japanese, Korean, etc.) w
## Using Components
-**In hooks** via `ctx.ui.custom()`:
+**In extensions** via `ctx.ui.custom()`:
```typescript
pi.on("session_start", async (_event, ctx) => {
@@ -337,7 +339,7 @@ class MySelector {
}
```
-Usage in a hook:
+Usage in an extension:
```typescript
pi.registerCommand("pick", {