Pi Agent Rust

pi_agent_rust

pi_agent_rust - Native AI coding agent CLI written in Rust

Why Should You Care? • TL;DR • Methodology • Quick Start • Features • Installation • Commands • Configuration

Rust 2024 License: MIT + Rider No Unsafe Code

```bash # Install latest release curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | bash ``` --- ## The Problem You want an AI coding assistant in your terminal, but existing tools are: - **Slow to start**: Managed runtimes can add noticeable startup overhead - **Resource intensive**: Electron apps or heavy runtimes can add substantial overhead - **Unreliable**: Streaming breaks, sessions corrupt, tools fail silently - **Hard to extend**: Closed ecosystems or complex plugin systems ## The Solution **pi_agent_rust** is a from-scratch Rust port of [Pi Agent](https://github.com/badlogic/pi) by [Mario Zechner](https://github.com/badlogic) (made with his blessing!). Official release archives install the single end-user binary `pi`, with streaming responses and 36 built-in tools (19 in the default `--tools` list; 14 always in the model's schema, the rest reachable through the `xdev` dispatcher or enabled in settings). ### Current product direction This project is no longer trying to be a strict drop-in replacement for the legacy TypeScript Pi. That target became both impractical and undesirable as the legacy implementation evolved. Legacy Pi remains useful historical context, but it is not our compatibility authority or definition of completeness. OMP is the closer reference for where the product is going: feature surface, agent workflows, look and feel, and overall UI/UX. Pi Rust still chooses Rust-native architecture and may intentionally differ from both projects when that produces a simpler, safer, or better coding agent. Historical drop-in and parity artifacts remain in the repository as records; they do not gate product work, releases, or user-facing claims. All repository quality checks, builds, and releases run through Doodlestein Self-Releaser (DSR). Contributors must not invoke Cargo or RCH directly, and GitHub Actions is never an execution or evidence authority for this project. Use `dsr quality --tool pi_agent_rust` for the registered quality recipe and the canonical DSR build/release commands documented in [docs/releasing.md](docs/releasing.md). For signed published payload verification and offline CLI smoke checks, see [Published release consumer checks](docs/published-release-checks.md). Rather than a direct line-by-line translation, this port builds on two purpose-built Rust libraries: - **[asupersync](https://github.com/Dicklesworthstone/asupersync)**: A structured concurrency async runtime with built-in HTTP, TLS, and SQLite - **[rich_rust](https://github.com/Dicklesworthstone/rich_rust)**: A Rust port of [Rich](https://github.com/Textualize/rich) by [Will McGugan](https://github.com/willmcgugan), providing beautiful terminal output with markup syntax ```bash # Start a session pi "Help me refactor this function to use async/await" # Continue a previous session pi --continue # Single-shot mode (no session) pi -p "What does this error mean?" < error.log ``` ## Why Should You Care? If you already use Pi Agent, especially through OpenClaw, this project keeps the core workflow while upgrading the engine under the hood: - **A native single-binary design** intended to minimize startup and runtime overhead - **A bounded-resource architecture** for long-running sessions - **A capability-gated security model** for extension/tool execution, including command-level blocking of dangerous extension shell patterns Security is a first-class design goal here, not a bolt-on: - Capability-gated hostcalls (`tool`/`exec`/`http`/`session`/`ui`/`events`) - Two-stage extension `exec` enforcement: capability gate first, then command mediation that blocks critical shell classes by default (for example recursive delete, disk/device writes, reverse shell) and can tighten to block high-tier classes in strict/safe policy - Policy + runtime risk + quota enforcement on the execution path - Per-extension trust lifecycle (`pending` -> `acknowledged` -> `trusted` -> `killed`) with kill-switch audit logs and explicit operator provenance - Hostcall-lane emergency controls that can force compatibility-lane execution globally or for one extension when fast-lane behavior needs immediate containment - Structured concurrency via `asupersync` for more predictable cancellation/lifecycle behavior - Auditable runtime signals/ledgers and redacted security alerts for extension behavior ## TL;DR (Pi/OpenClaw Users) The Rust port is designed around large-session, multi-agent, and extension-heavy workloads. Release-facing performance numbers are published only when the checked-in evidence artifacts are current, have matching run provenance, and show data and a passing result for every declared budget, with no data-contract failures. Historical benchmark snapshots are retained in planning/evidence artifacts, but they are not treated as current README claims until the performance evidence gate is regenerated cleanly. Extension runtime guarantees are also concrete: | Extension assurance signal | Why you should care | |---|---| | Two-stage `exec` guard (`exec` capability policy + command-level mediation + DCG/heredoc AST signals) | Dangerous shell intent is caught before spawn, including destructive payloads hidden in multiline wrappers | | Trust lifecycle + kill switch (`pending/acknowledged/trusted/killed`) | You can quarantine an extension instantly, log who pulled the switch and why, and require explicit re-acknowledgement before restoring access | | Hostcall lane kill-switch controls (`forced_compat_global_kill_switch`, `forced_compat_extension_kill_switch`) | Fast-path regressions can be contained immediately by forcing compatibility-lane execution without disabling the extension system | | Deterministic hostcall reactor mesh (shard affinity, bounded SPSC lanes, backpressure telemetry, optional NUMA slab tracking) | Runtime behavior stays predictable under contention; queue pressure and routing decisions are observable instead of opaque | | Cold owner-isolated JS realms + persistent transpile cache | Every reload gets a fresh realm while versioned disk-cached transpilation avoids treating mutable JavaScript state as safely reusable | | Tamper-evident runtime risk ledger (`verify` / `replay` / `calibrate`) | Security decisions are hash-linked and can be replayed or threshold-tuned from real runtime traces | Bottom line: Pi's architecture targets lower latency, lower memory use, and stronger extension runtime safety under real workload pressure; current numeric claims must come from fresh, provenance-matched evidence artifacts. Data source: `docs/planning/BENCHMARK_COMPARISON_BETWEEN_RUST_VERSION_AND_ORIGINAL__GPT.md` (latest secure-path + full orchestrator checkpoints, 2026-04-23). ### README Citation Convention Release-facing numeric performance claims in this README include inline citations with format: `*(from [artifact-path], run [correlation-id])*` Example: `*(from [artifact-path], run [correlation-id])*` Two additional machine-recognized citation forms exist: - `*(from [artifact-path])*` — path-only citation. The cited artifact must exist and parse; freshness is enforced by the same 14-day rule as release-facing claims. - `*(from [artifact-path]; historical snapshot)*` — explicit historical contract. The citation itself declares the obligation a retained snapshot: existence and validity are still checked, but staleness is not enforced because such claims never satisfy current release-facing requirements. `scripts/check_readme_evidence_freshness.py` (a pre-release check listed in [docs/releasing.md](docs/releasing.md), not part of the code quality recipe) checks file freshness and artifact content so stale, no-data, or correlation-mismatched evidence cannot back user-facing performance claims; for release-facing citations of `budget_summary.json` it validates the full `pi.perf.budget_summary.v2` contract, including that the header counts equal the per-budget rows. It reports line-numbered proof obligations for cited claims and extracts claim-gated performance phrases for reviewer audit. Historical snapshot citations are mapped separately and do not satisfy current release-facing claims. ## Performance-Oriented Architecture In this README, `we` means the project owner and collaborating coding agents. The design concentrates performance work in several runtime layers rather than assuming one optimization proves an end-to-end result. | Technique | What we do | Runtime intent | |---|---|---| | Cold-start minimization | Single native binary, no Node/Bun runtime bootstrap, no JIT warmup, startup prewarm for extension runtime paths | Reduce time-to-first-interaction | | Less copying on hot paths | `Arc`/`Cow` message flow, zero-copy hostcall/tool payload handling, reduced clone-heavy provider/session paths | Reduce CPU and allocation pressure | | Deterministic dispatch core | Typed hostcall opcodes, fast-lane/compat-lane routing, bounded shard queues with reactor-mesh telemetry | Reduce tail latency under concurrent extension load | | Efficient long-session storage | SQLite session index + v2 sidecar (segmented log + offset index) with O(index+tail) reopen path | Avoid full-history work on eligible resumes | | Streaming parser tuned for real networks | SSE parser tracks scanned bytes, handles UTF-8 tails, normalizes chunk boundaries, interns event-type strings | Reduce repeated scanning and parser stalls | | Safe fast-path controls | Shadow dual execution sampling, automatic backoff on divergence/overhead, compatibility-lane kill switches for containment | Bound optimization risk and preserve fallback behavior | | DSR performance governance | Scenario matrices, strict artifact contracts, fail-closed perf gates | Detect regressions before release | If you want the full implementation inventory, see [Performance Engineering](#performance-engineering). ## Benchmark Methodology and Claim Integrity The benchmark evidence policy is designed to keep results realistic, reproducible, and hard to game. What we measured: - **Matched-state workloads**: resume a large session and append the same 10 messages. - **Realistic E2E workloads**: resume + append + extension activity + slash-style state changes + forks + exports + compactions. - **Scale levels**: from `100k` up to `5M` token-class session states. - **Startup/readiness**: command-level readiness (`--help`, `--version`) separately from long-session workflows. How we kept comparisons fair: - **Two scopes** in the benchmark report: - apples-to-apples (`pi_agent_rust` vs legacy `coding-agent`) - apples-to-oranges (legacy stack components included where legacy behavior is outsourced) - **Release-mode binaries** and repeated runs per matrix cell. - **No paid-provider noise** in core latency/footprint tables (provider-call costs are excluded from these core comparisons). How we kept claims honest: - **Security controls stayed on** during secure-path measurements (no policy/risk/quota bypasses for speed claims). - **Raw artifacts are preserved** (JSON/trace/time outputs) and called out in the benchmark report. - **Blockers are explicitly disclosed**: when direct legacy reruns were blocked by missing workspace deps, we state that and compare against prior validated legacy artifacts instead of pretending reruns succeeded. - **Interpretation notes are explicit**: the report distinguishes baseline sections vs fresh reruns so readers can see exactly which values came from which run set. - **Reproducibility over marketing**: methodology, caveats, and known limits are included alongside wins. If you want full details, see: - `docs/planning/BENCHMARK_COMPARISON_BETWEEN_RUST_VERSION_AND_ORIGINAL__GPT.md` (methodology + results + caveats + raw artifact paths) ## Why Pi? | Feature | Pi (Rust) | Typical TS/Python CLI | |---------|-----------|----------------------| | **Startup** | Native single-binary path (Fresh `v0.3.0` measurement pending; pre-v0.3.0 criterion: ~5-7ms p95 version, ~12-15ms help; see `tests/perf/reports/budget_summary.json` `startup_version_p95` and `startup_full_agent_p95`) | Runtime-dependent | | **Binary size** | Size-budgeted release profile (LTO, strip, `opt-level = "z"`); the `binary_size_release` budget and its latest stripped-artifact measurement are reported in [Current Evidence State](#current-evidence-state), never promoted here until claim readiness is `ready` | Runtime-dependent | | **Memory (idle)** | Bounded-resource design; the `idle_memory_rss` budget and its latest release-binary measurement are reported in [Current Evidence State](#current-evidence-state) (`docs/perf-budgets-recipe.md` defines the canonical 5-measurement taxonomy) | Runtime-dependent | | **Streaming** | Native SSE parser | Library-dependent | | **Tool execution** | Process tree management | Basic subprocess | | **Sessions** | JSONL with branching | Varies | | **Unsafe code** | Forbidden | N/A | ## Quick Example ```bash # 1) Start an interactive session pi # 2) Ask a codebase question pi "Summarize the architecture in src/" # 3) Attach a file inline pi @src/main.rs "Explain startup flow" # 4) Run single-shot mode for scripting pi -p "List likely regression risks for this diff" # 5) Continue your last project session pi --continue # 6) Inspect available models/providers pi --list-models pi --list-providers ``` --- ## Foundation Libraries ### asupersync [asupersync](https://github.com/Dicklesworthstone/asupersync) is a structured concurrency async runtime designed for applications that need predictable resource cleanup. Key features used by pi_agent_rust: - **Capability-based context (`Cx`)**: Async functions receive an explicit context that controls what they can do (HTTP, filesystem, time). This makes testing deterministic. - **HTTP client with TLS**: Built-in HTTP API with rustls, avoiding OpenSSL dependency hell - **Structured cancellation**: When a parent task cancels, all child tasks cancel cleanly. No orphaned futures. `pi_agent_rust` runs on `asupersync` end-to-end today (runtime + HTTP/TLS + cancellation). Provider streaming uses a minimal HTTP client (`src/http/client.rs`) feeding a custom SSE parser (`src/sse.rs`). ### rich_rust [rich_rust](https://github.com/Dicklesworthstone/rich_rust) is a Rust port of Will McGugan's [Rich](https://github.com/Textualize/rich) Python library. It provides: - **Markup syntax**: `[bold red]error[/]` renders as bold red text - **Tables**: ASCII/Unicode table rendering with alignment and borders - **Panels**: Boxed content with titles - **Progress bars**: Animated progress indicators - **Markdown**: Terminal-rendered markdown with syntax highlighting - **Themes**: Consistent color schemes across components The terminal UI uses rich_rust for all output formatting, providing the same visual quality as Rich-based Python tools. --- ## Quick Start ### 1. Install ```bash # Install latest release binary curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | bash ``` If you already have the original TypeScript `pi` installed, the installer asks whether to make Rust Pi canonical as `pi` and automatically create `legacy-pi` for the old command. ### 2. Configure API Key ```bash export ANTHROPIC_API_KEY="sk-ant-..." ``` ### 3. Run ```bash # Interactive mode pi # With an initial message pi "Explain this codebase structure" # Read files as context pi @src/main.rs "What does this do?" ``` ### Using a local model `ollama`, `llamacpp` (llama.cpp's `llama-server`), `mistralrs` (mistral.rs), and `lmstudio` are built-in **local** providers. The first three need **no API key** and work out of the box against their default ports: ```bash pi --provider ollama --model llama3 -p "hi" pi --provider llamacpp --model -p "hi" pi --provider mistralrs --model default -p "hi" ``` To point at any other OpenAI-compatible server (a custom host/port, vLLM, etc.), add it to `~/.pi/agent/models.json`: ```json { "providers": { "ollama": { "api": "openai-completions", "baseUrl": "http://127.0.0.1:11000/v1", "apiKey": "ollama", "models": [{ "id": "Qwen3.6-35B-A3B-4bit", "contextWindow": 32768 }] } } } ``` Then `pi --provider ollama --model Qwen3.6-35B-A3B-4bit`. See [docs/models.md](docs/models.md) for the full `models.json` schema, provider aliases, and secret resolution (env vars and `!command` shell lookups). ### Refreshing provider model catalogs For OpenAI-compatible providers, model discovery is a standalone command: it prints one model ID per stdout line and exits without starting the TUI. ```bash # Use a successful live response or (with a warning on stderr) the static # registry when live discovery is unavailable pi --fetch-models openrouter # Bypass the cache and require a genuinely live response; never fall back pi --fetch-models openrouter --refresh-models # Make a successful live/cache catalog available to future --list-models and # interactive /model pickers pi --fetch-models openrouter --refresh-models --persist-models ``` Each standalone CLI invocation starts a new process, so its in-memory cache is fresh. The five-minute cache only avoids repeat discovery calls made within one long-lived process by SDK/library users; `--refresh-models` bypasses that cache. Discovery also reads usable `supported_reasoning_levels` advertisements, including `metadata.supported_reasoning_levels` and entries shaped as `{"effort":"high"}`. Nested metadata takes precedence. Pi preserves the advertised tiers through the cache and persisted catalog, constrains the model's thinking choices to those tiers, and sends the selected effort through the provider's request format. The recognized tiers are `off` (also advertised as `none`), `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. Missing, empty, or unusable advertisements leave existing model capabilities intact. Your configured thinking level remains authoritative; discovery does not select a server-advertised default effort. Persistence is opt-in. The v2 `~/.pi/agent/models.fetched.json` schema stores provider/model IDs, optional bounded reasoning tiers, the fetch timestamp, and a non-secret SHA-256 identity binding membership to the provider, API, query-free endpoint, auth-header mode, recognized credential-query ordered name/presence shape, and request-header name/presence shape that produced it. Pi never persists a static fallback, API credentials, URL query values, or request-header values—not even as offline-verifiable hashes. Credential-channel values are rotation-tolerant. Any non-empty query/header value outside a narrowly recognized credential channel may identify a tenant or deployment, so Pi refuses to persist that catalog (and ignores legacy persisted rows for such a current route) rather than reuse unverifiable membership. If a safely bound route shape no longer matches, Pi ignores those generated rows and reports how to refresh them. Credential rotation alone does not invalidate the catalog. The generated membership is likewise not account-bound: switching accounts on the same endpoint/transport shape can retain the prior account's saved model list until you rerun `--fetch-models --refresh-models --persist-models`. Inference still resolves and sends the current account's credential; only the opt-in model-membership list can be stale across that switch. The generated catalog is loaded first; your hand-written `~/.pi/agent/models.json` is loaded afterward and remains authoritative. Pi does not rewrite or merge that user-authored file. Legacy `pi.models.fetched.v1` files cannot be rebound safely because they lack this provenance, so Pi preserves them instead of overwriting them. Move the legacy file aside to `models.fetched.v1.backup.json`, then rerun the verified live refresh and persist command above to create a v2 catalog. --- ## Features ### Streaming Responses Real-time response streaming with extended thinking support: ``` pi "Write a quicksort implementation" ``` Watch the response appear incrementally, with thinking blocks shown inline. ### 36 Built-in Tools Tools are tiered so the model's live schema stays small while everything remains reachable. The tier table lives in `src/xdev.rs`; the default `--tools` list lives in `src/cli.rs`: - **Essential** (always in the provider schema): `read`, `write`, `edit`, `bash`, `grep`, `find`, `ls`, `hashline_edit`, `ask`, `todo`, `web_search`, `submit_plan`, `current_time`, `xdev` - **Discoverable** (registered, hidden from the schema until promoted via `xdev list/describe/run/promote`): `ast_grep`, `ast_edit`, `lsp`, `debug`, `manage_skill` — plus the memory-bank tools (`retain`, `recall`, `reflect`, `memory_edit`, `learn`) when `memory.backend` is `local` or `cass` (local memory plus read-only project history) - **Default-enabled**: `jobs` (background bash job control) and `hub` (PTY service supervision), alongside the essential tier. The default `--tools` list names 19 tools; the registry always adds `manage_skill` and, when any discoverable tool is enabled, the `xdev` dispatcher - **`--tools` opt-in extras**: `eval`, `github`, `security_scan` - **Settings-gated extras** (off until enabled in `settings.json`): `browser` (`browser.enableBrowser`), `computer` (`computer.enableComputer`), the media trio `inspect_image`, `generate_image`, `tts` (`media.enableInspectImage` / `media.enableGenerateImage` / `media.enableTts`), and `read_media` (`media.enableReadMedia`; inline video/audio for Gemini-family models) - **Opt-in only**: `subagent` (it can start additional coding-agent processes) | Tool | Description | |------|-------------| | `read` | Read files (images and http(s)/`skill://`-style URLs supported) | | `write` / `edit` / `hashline_edit` | Create, surgically replace, or hashline-anchored edit files | | `bash` | Shell with timeout, command mediation, optional PTY, background jobs | | `grep` / `find` / `ls` | In-process content search, file discovery, listing | | `web_search` | Ranked multi-provider web search with circuit breaking | | `ask` / `todo` | Structured mid-turn option cards; persistent session task list | | `submit_plan` | Submit a completed plan for approval when plan mode is active | | `current_time` | The host's wall-clock time: UTC and local ISO-8601 timestamps, the UTC offset, Unix epoch seconds, weekday, and ISO week (the local zone follows `TZ`); takes no arguments. The system prompt carries only the date so the cached prefix stays stable; this tool is the clock | | `xdev` | Dispatcher exposing the discoverable tier (`list/describe/run/promote`) | | `ast_grep` / `ast_edit` | Structural code search and rewrite | | `lsp` / `debug` | Language-server (14 ops) and DAP debugging (29 ops) bridges | | `eval` | Persistent Python and JS kernels with cell semantics | | `jobs` / `hub` | Background bash job control; PTY service supervision | | `github` | `gh`-backed PR/issue/run operations | | `security_scan` | Rule-pack security scanning to SARIF (`plan`/`run`/`disposition`/`compare`) | | `manage_skill` + memory tools | Managed skills CRUD; opt-in project memory bank | | `browser` | Headless Chromium automation over CDP (navigate, snapshot, click, type, screenshot) with a domain allowlist; settings-gated | | `computer` | Desktop automation (displays, windows, screenshots, mouse/keyboard, clipboard); mutating actions require approval; settings-gated | | `inspect_image` / `generate_image` / `tts` | Vision analysis of local images, image generation/editing, and text-to-speech through provider adapters; settings-gated | | `read_media` | Attaches a local video/audio file (mp4, webm, mov, mp3, wav, m4a, ogg, flac) as an inline media block. Gemini, Gemini CLI, and Vertex Gemini models receive it natively as `inline_data`; every other provider sees `[media omitted: , , ]`. Hard cap 5 MiB per file (`media.maxBytes`); settings-gated | | `subagent` | Delegate isolated work to named Rust Pi child agents | All tools include automatic truncation for large outputs (2000 lines / 1MB), detailed metadata in responses, and process-tree cleanup for bash. Background-job logs live in a dedicated directory with a 256 MiB / 4096-entry budget. When it cannot admit another 16 MiB artifact, Pi deletes the oldest unlocked logs, only as many as needed, and always keeps active logs and at least eight recent ones. Set `PI_JOBS_ARTIFACT_RETENTION=preserve` to keep every log instead; Pi then refuses new background jobs once the budget is full. Job snapshots report the applied policy, removed-file count, and reclaimed bytes in `artifactCleanup`. Hub service logs retain the first 16 MiB of raw output per run. Pi continues draining the service after that limit or an artifact write failure, so live tail logs, readiness checks, and PTY input continue working. `logs`, `ps`, and `describe` report `logCapture` byte counts, truncation, I/O errors, and output drain state separately from process status; incremental reads also report evicted lines. The cap applies to each artifact, not the total across runs. `detached: true` skips session-exit cleanup, but the PTY and its supervisor still belong to the current Pi process: cross-process reattachment and survival after that host process exits are not implemented. Per-tool exposure is configurable via `tools.loadMode.` set to `essential`, `discoverable`, or `off`; an explicit `--tools` list always wins: ```bash pi --tools read,bash,edit,write,grep,find,ls,hashline_edit,subagent \ "Use the scout agent to inspect the provider implementation." ``` ### Native Subagents and Orchestration Rust Pi includes a native `subagent` tool; it does not depend on a QuickJS extension and never resolves a child executable by assuming a `pi` binary on `PATH`. By default it starts the current Rust Pi executable. Set `PI_SUBAGENT_PI_BINARY=/absolute/path/to/rpi` only when an explicit binary override is needed. Agent definitions are Markdown files in `$PI_CODING_AGENT_DIR/agents/*.md` (normally `~/.pi/agent/agents/*.md`) or the nearest `.pi/agents/*.md`. Project definitions take precedence over same-named user definitions. The process inherits the parent's provider, router, authentication, and model-registry environment, including `PI_CODING_AGENT_DIR`. Children choose their model in this order: the agent definition's `model:` pin, the configured `task` role (or `smol` fallback), then the parent's active provider and model. Each request captures the parent selection once, including any manual switch or failover already in effect; queued children, chain steps, schema retries, and explicit revivals retain that selection. Children resolve credentials from their inherited environment and existing authentication configuration. Credentials supplied only to the parent's CLI or in memory are not copied into child arguments or new environment variables. ```markdown --- name: scout description: Inspect code and return concise, evidence-backed findings. model: ai-router/gpt-5.6-sol reasoning: low tools: read,grep,find,ls skills: ../skills/codebase-archaeology/SKILL.md --- Read relevant code before answering. Do not edit files. ``` The tool accepts exactly one workflow shape: a single `{ agent, task }`, a bounded parallel `tasks` array (up to 8, default concurrency 4), or a sequential `chain` array. In chains, `{previous}` in a task is replaced by the preceding child's final output. Children run headlessly in isolated ephemeral sessions, stream progress into the parent TUI/JSON output, return structured status and stderr details, and are killed/reaped if the parent is cancelled. Child agents receive the declared tool allowlist; the default child allowlist deliberately excludes `subagent` to prevent accidental recursive delegation. With per-task `isolation: "worktree"`, a parallel batch captures each source workspace before launching children, including staged, unstaged, and untracked files. Queued children and corrective retries use that same baseline. Accepted patches apply after execution in task order; conflicts and cancelled work remain in their worktrees for inspection. `isoApply: "keep"` retains a result without applying it, and `isoApply: "drop"` discards its worktree after reporting the patch. In interactive mode, `/tan ` starts the same task-role child machinery without interrupting the main conversation. The child runs in the current directory, appears in `hub agent roster` with `kind=tan`, and sends its bounded completion summary through the follow-up queue at the next idle turn boundary. Because `/tan` inherits the delegation safety gate, it is available only when the opt-in `subagent` tool is enabled. It captures the same model precedence when the command is submitted, so a later parent model switch does not retarget it. Native children include `hub` in their default tool set and can exchange messages with other children of the same parent Pi process. Agent definitions with an explicit tool allowlist must include `hub` to enable this capability. A child's `hub` call with `{"op":"agent","action":"roster"}` returns its authenticated `selfId` and the parent's child roster. Use those run IDs as recipients: ```json {"op":"agent","action":"send","name":"receiver-1","text":"The parser change is ready."} {"op":"agent","action":"inbox"} {"op":"agent","action":"send","name":"parent","text":"I found a blocking dependency."} ``` Sibling messages enter the recipient's steering queue between turns and remain available in its inbox. The parent reads child reports with `{"op":"agent","action":"inbox","name":"parent"}`. Inbox pages return `nextCursor`, `hasMore`, and `oldestCursor`; pass `nextCursor` as `cursor` to request later messages. Each recipient retains its latest 64 messages, so clients can use `oldestCursor` to detect that earlier messages have fallen outside retention. The parent authenticates the child's sender identity. Children can read their own inbox, list peers, and send to a live sibling or the parent; transcript, steering, kill, and revival controls remain on the parent surface. The local connection closes when its owning child run ends or is cancelled. ### Session Management Sessions persist as JSONL files with full conversation history: ```bash # Continue most recent session pi --continue # Open specific session pi --session ~/.pi/agent/sessions/--home-user-project--/2024-01-15T10-30-00.jsonl # Ephemeral (no persistence) pi --no-session ``` Sessions support: - Tree structure for conversation branching - Model/thinking level change tracking - Automatic compaction for long conversations ### Extended Thinking Enable deep reasoning for complex problems: ```bash pi --thinking high "Design a distributed rate limiter" ``` Thinking levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` ### Customization (Skills & Prompt Templates) - **Skills**: Drop `SKILL.md` under `~/.pi/agent/skills/` or `.pi/skills/` and invoke with `/skill:name`. - **Prompt templates**: Markdown files under `~/.pi/agent/prompts/` or `.pi/prompts/`; invoke via `/