docs(coding-agent): update README-NEW.md, tui.md, add new docs

- README-NEW.md: add environment variables, philosophy extras (no built-in to-dos, no background bash), session ID support, pi config command, plain git URLs, version pinning
- tui.md: fix hooks->extensions terminology, update Component interface (invalidate required, add wantsKeyRelease)
- Add new docs: settings.md, development.md, json.md
- Add screenshots: tree-view.png, doom-extension.png
This commit is contained in:
Mario Zechner 2026-01-26 02:27:19 +01:00
parent 28ab25b07e
commit 5340862910
7 changed files with 626 additions and 107 deletions

View file

@ -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
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

View file

@ -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")'
```

View file

@ -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 }
}
```

View file

@ -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", {