cd /news/ai-tools/pi-rust-high-performance-ai-coding-a… Β· home β€Ί topics β€Ί ai-tools β€Ί article
[ARTICLE Β· art-48772] src=github.com β†— pub= topic=ai-tools verified=true sentiment=↑ positive

Pi (Rust): High-performance AI coding agent CLI written in Rust

Pi (Rust), a high-performance AI coding agent CLI written in Rust, has been released as a port of the original Pi Agent. It offers instant startup, stable streaming, and a smaller memory footprint compared to Node.js or Python-based tools, with security features like capability-gated hostcalls and two-stage extension enforcement. The tool is designed for large-session, multi-agent, and extension-heavy workloads.

read53 min views1 publishedJul 7, 2026
Pi (Rust): High-performance AI coding agent CLI written in Rust
Image: source

pi_agent_rust - High-performance AI coding agent CLI written in Rust

Why Should You Care? β€’ TL;DR β€’ Methodology β€’ Quick Start β€’ Features β€’ Installation β€’ Commands β€’ Configuration

curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | bash

You want an AI coding assistant in your terminal, but existing tools are:

Slow to start: Node.js/Python runtimes add 500ms+ before you can type** Memory hungry**: Electron apps or heavy runtimes eat gigabytes** Unreliable**: Streaming breaks, sessions corrupt, tools fail silently** Hard to extend**: Closed ecosystems or complex plugin systems

pi_agent_rust is a from-scratch Rust port of Pi Agent by Mario Zechner (made with his blessing!). Single binary, instant startup, stable streaming, and 8 built-in tools.

Rather than a direct line-by-line translation, this port builds on two purpose-built Rust libraries:

: A structured concurrency async runtime with built-in HTTP, TLS, and SQLiteasupersync: A Rust port ofrich_rustRichbyWill McGugan, providing beautiful terminal output with markup syntax

pi "Help me refactor this function to use async/await"

pi --continue

pi -p "What does this error mean?" < error.log

If you already use Pi Agent, especially through OpenClaw, this project keeps the core workflow while upgrading the engine under the hood:

Substantially faster in realistic end-to-end flows(not synthetic microbenchmarks)** Dramatically smaller memory footprintin long-running sessions Materially stronger 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

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 report no CI no-data or 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
Startup prewarm + warm isolate reuse for JS runtimes Runtime creation overlaps startup and warm reuse keeps repeated extension runs low-latency without a Node/Bun process model
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).

All numeric performance claims in this README include inline citations with format: *(from [artifact-path], run [correlation-id])*

Example: *(from [artifact-path], run [correlation-id])*

CI checks both file freshness and artifact content so stale, no-data, or correlation-mismatched evidence cannot back user-facing performance claims. The README evidence checker reports line-numbered proof obligations for cited claims and extracts claim-gated performance phrases for reviewer audit. Explicit historical snapshot citations are mapped separately and do not satisfy current release-facing claims.

In this README, we

means the project owner and collaborating coding agents.

The speed gains come from runtime design, not one trick.

Technique What we do Runtime effect
Cold-start minimization Single static binary, no Node/Bun runtime bootstrap, no JIT warmup, startup prewarm for extension runtime paths Faster 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
Lower CPU and allocation pressure
Deterministic dispatch core Typed hostcall opcodes, fast-lane/compat-lane routing, bounded shard queues with reactor-mesh telemetry Better 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 Fast resume on large histories
Streaming parser tuned for real networks SSE parser tracks scanned bytes, handles UTF-8 tails, normalizes chunk boundaries, interns event-type strings Lower streaming overhead and fewer parser stalls
Safe fast-path controls Shadow dual execution sampling, automatic backoff on divergence/overhead, compatibility-lane kill switches for containment Keeps optimizations fast without silent behavior drift
CI-level performance governance Scenario matrices, strict artifact contracts, fail-closed perf gates Regressions are caught before release

If you want the full implementation inventory, see Performance Engineering.

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**: from100k

up to5M

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 legacycoding-agent

) - apples-to-oranges (legacy stack components included where legacy behavior is outsourced)

  • apples-to-apples ( 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)

Feature Pi (Rust) Typical TS/Python CLI
Startup
<100ms 500ms-2s
Binary size
~21.1 MiB (default release) 100MB+ (with runtime)
Memory (idle)
<50MB 200MB+
Streaming
Native SSE parser Library-dependent
Tool execution
Process tree management Basic subprocess
Sessions
JSONL with branching Varies
Unsafe code
Forbidden N/A
pi

pi "Summarize the architecture in src/"

pi @src/main.rs "Explain startup flow"

pi -p "List likely regression risks for this diff"

pi --continue

pi --list-models
pi --list-providers

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 (: Async functions receive an explicit context that controls what they can do (HTTP, filesystem, time). This makes testing deterministic.Cx

)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 is a Rust port of Will McGugan's Rich Python library. It provides:

Markup syntax:[bold red]error[/]

renders as bold red textTables: 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.

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.

export ANTHROPIC_API_KEY="sk-ant-..."
pi

pi "Explain this codebase structure"

pi @src/main.rs "What does this do?"

Real-time token streaming with extended thinking support:

pi "Write a quicksort implementation"

Watch the response appear token-by-token, with thinking blocks shown inline.

Tool Description Example
read
Read file contents, supports images Read src/main.rs
write
Create or overwrite files Write a new config file
edit
Surgical string replacement Fix the typo on line 42
hashline_edit
Precise edits using LINE#HASH tags Apply edits to specific lines using hashline anchors
bash
Execute shell commands with timeout Run the test suite
grep
Search file contents with context Find all TODO comments
find
Discover files by pattern Find all *.rs files
ls
List directory contents What's in src/?

All tools include:

  • Automatic truncation for large outputs (2000 lines / 1MB)
  • Detailed metadata in responses
  • Process tree cleanup for bash (no orphaned processes)

Sessions persist as JSONL files with full conversation history:

pi --continue

pi --session ~/.pi/agent/sessions/--home-user-project--/2024-01-15T10-30-00.jsonl

pi --no-session

Sessions support:

  • Tree structure for conversation branching
  • Model/thinking level change tracking
  • Automatic compaction for long conversations

Enable deep reasoning for complex problems:

pi --thinking high "Design a distributed rate limiter"

Thinking levels: off

, minimal

, low

, medium

, high

, xhigh

Skills: DropSKILL.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/<template> [args]

.Packages: Share bundles withpi install npm:@org/pi-packages

(skills, prompts, themes, extensions).

Pi provides context-aware autocomplete in the interactive editor:

: Type@

file references@

followed by a path fragment to attach file contents. The completion engine indexes project files (respecting.gitignore

) via theignore

crate'sWalkBuilder

, capping at 5,000 entries.: Built-in commands (/

slash commands/help

,/model

,/tree

,/clear

,/compact

,/exit

) and user-defined prompt templates and skills all appear as completions.Fuzzy scoring: Prefix matches rank above substring matches. Results are sorted by match quality, then by kind (commands > templates > skills > files > paths).Background refresh: A background thread re-indexes the project file tree every 30 seconds, so completions stay current without blocking the input loop.

Pi runs in three modes, each suited to different workflows:

Mode Invocation Use Case
Interactive
pi (default)
Full TUI with streaming, tools, session branching, autocomplete
Print
pi -p "..."
Single response to stdout, no TUI, scriptable
RPC
pi --mode rpc
Headless JSON protocol over stdin/stdout for IDE integrations

Interactive mode provides the full experience: a multi-line text editor with history, scrollable conversation viewport, model selector (Ctrl+L

), scoped model cycling (Ctrl+P

/Ctrl+Shift+P

), session branch navigator (/tree

), and real-time token/cost tracking.

Print mode sends one message, streams the response to stdout, and exits. Useful for shell scripts and one-off queries.

RPC mode exposes a line-delimited JSON protocol for programmatic control. Clients send commands (prompt

, steer

, follow-up

, abort

, get-state

, compact

) and receive streaming events. This is how IDE extensions and custom frontends integrate with Pi. See RPC Protocol for the wire format.

Pi supports two extension runtime families with capability-gated host connectors:

JS/TS entrypoints run

without Node or Bun in an embedded QuickJS runtime. - *.native.json

descriptors run in the native-rust descriptor runtime. - Extension entrypoints are auto-detected:

.js/.ts/.mjs/.cjs/.tsx/.mts/.cts

run directly in embedded QuickJS (no descriptor conversion).*.native.json

loads the native-rust descriptor runtime.- One session currently uses one runtime family at a time (JS/TS or native descriptor).

Sub-100ms cold load(P95),** sub-1ms warm load**(P99) - Node API shims for

fs

,path

,os

,crypto

,child_process

,url

, and more - Capability-based security: extensions call explicit connectors (

tool/exec/http/session/ui

) with audit logging - Command-level exec mediation: dangerous shell signatures are classified and blocked before spawn, with redacted denial alerts and mediation ledger entries

Trust-state lifecycle and kill-switch controls with audited state transitions (

pending

/acknowledged

/trusted

/killed

) - Hostcall reactor mesh with deterministic shard routing, bounded queue backpressure, and optional NUMA-aware telemetry

Runtime prewarm path with warm isolate reuse so extension startup cost is mostly paid before the first prompt

/model

(orCtrl+L

) opens a selector focused on models that are ready to run with current credentials.Ctrl+P

andCtrl+Shift+P

cycle through the scoped model set without opening the overlay.- Provider IDs and aliases are matched case-insensitively in model selection and /login

. - Models that do not require configured credentials can run keyless.

Extensions can register tools, slash commands, event hooks, flags, providers, and shortcuts. See EXTENSIONS.md for the full architecture and docs/extension-catalog.json for the 223-entry catalog with per-extension conformance status and perf budgets.

This project validates extension compatibility with a three-track pipeline:

Vendored corpus (224): deterministic conformance, compatibility matrix, and scenario suites.** Unvendored corpus (777): source acquisition and onboarding prioritization. Release-binary live-provider E2E**: realtarget/release/pi

execution against a non-mocked provider/model path.

  • Catch runtime/API regressions in QuickJS host shims and capability policy.

  • Catch dangerous extension shell call patterns with real command mediation on the release binary path.

  • Verify extension behavior against real provider responses, not just fixture/mocked flows.

  • Keep extension support measurable instead of anecdotal.

  • Produce a prioritized queue for onboarding unvendored candidates into vendored conformance.

Fetch unvendored source corpus- Binary: ext_unvendored_fetch_run

  • Typical command: cargo run --example ext_unvendored_fetch_run -- run-all --workers 8 --no-probe

  • Purpose:

  • Clones GitHub repos and unpacks npm tarballs into .tmp-codex-unvendored-cache/

  • Produces machine-readable acquisition status for all unvendored candidates

  • Clones GitHub repos and unpacks npm tarballs into

  • Artifacts: tests/ext_conformance/reports/pipeline/unvendored_fetch_probe_report.json

tests/ext_conformance/reports/pipeline/unvendored_fetch_probe_events.jsonl

  • Binary:

Run end-to-end validation orchestration- Binary: ext_full_validation

  • Typical command: cargo run --example ext_full_validation --

  • Stages (in order): refresh_onboarding_queue

(runsext_onboarding_queue

)conformance_shard_0..N

(runsext_conformance_generated

sharded matrix)conformance_failure_dossiers

provider_compat_matrix

scenario_conformance_suite

auto_repair_full_corpus

differential_suite

(optional, enabled via--run-diff

; npm diff via--run-npm-diff

)

  • Artifacts: tests/ext_conformance/reports/pipeline/full_validation_report.json

tests/ext_conformance/reports/pipeline/full_validation_report.md

  • Plus stage-specific reports under tests/ext_conformance/reports/**

  • Binary:

Run dev-firstset live-provider gate (must pass before release build)- Binary: ext_release_binary_e2e

  • Typical command: cargo build --bin pi --bin ext_release_binary_e2e

PI_HTTP_REQUEST_TIMEOUT_SECS=0 target/debug/ext_release_binary_e2e --pi-bin target/debug/pi --provider ollama --model qwen2.5:0.5b --jobs 10 --timeout-secs 600 --max-cases 20 --extension-policy balanced --out-json tests/ext_conformance/reports/release_binary_e2e/ollama_firstset_dev_20260219_jobs10_timeout600.json --out-md tests/ext_conformance/reports/release_binary_e2e/ollama_firstset_dev_20260219_jobs10_timeout600.md

  • Purpose:

  • Proves the current codepath works end-to-end on a representative first-set before paying release-build cost.

  • Serves as the promotion gate to full release-binary validation.

  • Gate:

  • Require pass=20 / total=20

withfail=0

.

  • Require
  • Artifacts: tests/ext_conformance/reports/release_binary_e2e/ollama_firstset_dev_20260219_jobs10_timeout600.json

tests/ext_conformance/reports/release_binary_e2e/ollama_firstset_dev_20260219_jobs10_timeout600.md

  • Binary:

Run full release-binary live-provider E2E (after step 3 passes)- Binary: ext_release_binary_e2e

  • Typical command: cargo build --release --bin pi --bin ext_release_binary_e2e

PI_HTTP_REQUEST_TIMEOUT_SECS=0 target/release/ext_release_binary_e2e --pi-bin target/release/pi --provider ollama --model qwen2.5:0.5b --jobs 10 --timeout-secs 600 --extension-policy balanced --out-json tests/ext_conformance/reports/release_binary_e2e/ollama_full_release_20260219_jobs10_timeout600.json --out-md tests/ext_conformance/reports/release_binary_e2e/ollama_full_release_20260219_jobs10_timeout600.md

  • Purpose:
  • Executes target/release/pi

directly for each selected extension case. - Uses a live provider/model path (default ollama

+qwen2.5:0.5b

) to exercise non-mocked end-to-end behavior. - Emits per-case stdout/stderr captures plus summary artifacts ( pi.ext.release_binary_e2e.v1

).

  • Executes
  • Artifacts: tests/ext_conformance/reports/release_binary_e2e/ollama_full_release_20260219_jobs10_timeout600.json

tests/ext_conformance/reports/release_binary_e2e/ollama_full_release_20260219_jobs10_timeout600.md

tests/ext_conformance/reports/release_binary_e2e/cases/*

  • Binary:

Aggregate and triagefull_validation_report.json

combines:- Stage-level pass/fail ( stageSummary

,stageResults

) - Corpus counts ( corpus

) - Vendored conformance totals ( conformance

) - Provider matrix totals ( providerCompat

) - Scenario totals ( scenario

) - Review queue + verdict classification ( reviewQueue

,verdictCounts

)

  • Stage-level pass/fail (
  • Important interpretation rule: not_tested_unvendored

indicates unvendored candidates not yet in vendored conformance; this is inventory status, not a vendored regression.

These runs compile many crates and can be disk-heavy. Point Cargo artifacts and temp files to a large volume:

export CARGO_TARGET_DIR="/data/tmp/pi_agent_rust_cargo/${USER:-agent}/target"
export TMPDIR="/data/tmp/pi_agent_rust_cargo/${USER:-agent}/tmp"
mkdir -p "$CARGO_TARGET_DIR" "$TMPDIR"

Then run:

cargo run --example ext_unvendored_fetch_run -- run-all --workers 8 --no-probe
cargo run --example ext_full_validation --

From:

tests/ext_conformance/reports/gate/must_pass_gate_verdict.json

(generated2026-05-15T17:03:02.000Z

, runlocal-20260515T170218075Z

) - tests/ext_conformance/reports/health_delta/health_delta_report.json

(generated2026-05-13T03:37:59.568Z

) - tests/ext_conformance/reports/journeys/journey_report.json

(generated2026-05-13T02:59:58.302Z

) - tests/evidence_bundle/index.json

(generated2026-05-12T19:26:21.441Z

, runlocal-20260512T192621Z

) - tests/full_suite_gate/certification_verdict.json

(generated2026-05-14T19:59:37.227Z

) - docs/evidence/dropin-certification-verdict.json

(generated2026-05-18T19:37:26Z

) - Strict drop-in status:

22/22 certification gates PASS, 16/16 blocking gates PASS-CERTIFIED

(from docs/evidence/dropin-certification-verdict.json; strict replacement wording remains governed by docs/contracts/dropin-certification-contract.json and this verdict artifact) - Unified evidence bundle:

29/29

sections present,0

missing,0

invalid*(from tests/evidence_bundle/index.json)* - Extension must-pass gate:

123/123

must-pass extensions passed; informational stretch set100/101

passed with one non-blocking stretch failure*(from tests/ext_conformance/reports/gate/must_pass_gate_verdict.json)* - Extension health delta:

223/223

tested extensions passed (100.0%

),0

regressions,13

fixes vs the 2026-02-07 baseline, with1

intentionally excluded test fixture disclosed in the report*(from tests/ext_conformance/reports/health_delta/health_delta_report.json)* - Health-delta full-manifest non-pass extensions:

0

;base_fixtures

is a test-only negative fixture excluded from release-facing pass-rate claims with disposition recorded indocs/evidence/extension-health-delta-failure-disposition.json

. - Extension journey coverage:

123/123

journey scenarios passed (100.0%

); command, event-subscriber, multi-capability, passive, and tool-provider categories are green*(from tests/ext_conformance/reports/journeys/journey_report.json)* - Stress triage:

1,500

events,0

errors, p99 latency396us

, RSS growth0.0%

(from tests/perf/reports/stress_triage.json, run bd-2zcs5.71-darkgoose-20260510T0058Z)

curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | bash

curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | bash -s -- --yes --easy-mode

curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | bash -s -- --version v0.1.0

curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | \
  bash -s -- \
    --artifact-url "https://github.com/Dicklesworthstone/pi_agent_rust/releases/download/v0.1.0/pi-linux-amd64.tar.xz" \
    --checksum-url "https://github.com/Dicklesworthstone/pi_agent_rust/releases/download/v0.1.0/SHA256SUMS"

curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/install.sh?$(date +%s)" | \
  bash -s -- --yes --no-completions

The installer is idempotent and supports a migration path from TypeScript Pi:

  • Detect existing TS pi

command - Prompt to install Rust Pi as canonical pi

  • Preserve old CLI behind legacy-pi

  • Record state for clean uninstall/restore

Notable installer flags:

--offline [TARBALL]

: enforce offline mode; optional local artifact path (.tar.gz

,.tar.xz

,.zip

, or raw binary)--artifact-url

: force a specific release artifact URL--checksum

/--checksum-url

: override checksum source for explicit artifacts--sigstore-bundle-url

: override Sigstore bundle URL used bycosign verify-blob

--completions auto|off|bash|zsh|fish

: force shell completion install target (off

is equivalent to--no-completions

)--no-completions

: disable completion installation--no-agent-skills

: skip automatic installation of thepi-agent-rust

skill into~/.claude/skills/

and~/.codex/skills/

--no-verify

: skip checksum + signature verification (testing only)--artifact-url

without--version

uses a synthetic tag for release mode only; if artifact download fails, install exits instead of attempting source fallback- Installer honors HTTPS_PROXY

/HTTP_PROXY

for all network fetches

By default, the installer also installs a pi-agent-rust

skill for both Claude Code and Codex CLI:

  • Claude Code: ~/.claude/skills/pi-agent-rust/SKILL.md

  • Codex CLI: ~/.codex/skills/pi-agent-rust/SKILL.md

(or$CODEX_HOME/skills/pi-agent-rust/SKILL.md

ifCODEX_HOME

is set) - During upgrades, installer-managed legacy pre-tool entries from older versions are removed automatically (idempotent, path-scoped, and non-destructive) when prior installer state is present.

Installer regression harness (options + checksum + signature + completions):

bash tests/installer_regression.sh

For migration adoption, packaging and invocation compatibility follows this contract:

This section covers packaging/invocation behavior only; functional parity and certification status are tracked in

docs/contracts/dropin-certification-contract.json

. - Canonical executable name is

pi

across release assets and installer-managed installs. - Installer-managed installs also create an

rpi

compatibility launcher when no conflictingrpi

command already exists on your PATH. - Existing TypeScript

pi

installs can be migrated in place; the prior command is preserved aslegacy-pi

. - If you keep TypeScript

pi

as canonical (--keep-existing-pi

), Rust Pi is installed aspi-rust

. - On Apple Silicon, the installer prefers the native arm64 artifact even when launched from a Rosetta-translated shell.

Version-pinned installs are supported via

install.sh --version vX.Y.Z

for deterministic rollouts. - Every GitHub release ships platform binaries plus

SHA256SUMS

for integrity validation.

Representative smoke checks:

command -v pi
pi --version
pi --help >/dev/null

command -v legacy-pi && legacy-pi --version

Requires Rust nightly (2024 edition features):

rustup install nightly
rustup default nightly

git clone https://github.com/Dicklesworthstone/pi_agent_rust.git
cd pi_agent_rust
cargo build --release

./target/release/pi --version

cargo install --path . --locked

Pi has minimal runtime dependencies:

fd

: Required for thefind

tool (install viaapt install fd-find

orbrew install fd

)rg

: Required for thegrep

tool (install viaapt install ripgrep

orbrew install ripgrep

)

curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/pi_agent_rust/main/uninstall.sh" | bash

By default, uninstall removes installer-managed Rust binaries/aliases and skill directories, then restores a migrated TypeScript pi

if one was preserved.

pi [OPTIONS] [MESSAGE]...

pi                              # Start interactive session
pi "Hello"                      # Start with message
pi @file.rs "Explain this"      # Include file as context
pi -p "Quick question"          # Print mode (no session)

Interactive file references:

  • Type @relative/path

in the editor to attach a file’s contents (autocomplete inserts the@

form).

Option Description
-c, --continue
Continue most recent session
-r, --resume
Open session picker UI
--session <PATH>
Open specific session file
--session-dir <DIR>
Override session storage directory for this run
`--session-durability strict balanced
--no-session
Don't persist conversation
-p, --print
Single response, no interaction
`--mode text json
--provider <NAME>
Force provider for this run (aliases supported)
--model <MODEL>
Model to use (auto-select fallback: anthropic/claude-sonnet-4-6 , then anthropic/claude-opus-4-7 , then openai/gpt-5.1-codex )
--thinking <LEVEL>
Thinking level: off/minimal/low/medium/high/xhigh
--tools <TOOLS>
Comma-separated tool list
--api-key <KEY>
API key (or use provider-specific env vars such as ANTHROPIC_API_KEY , OPENAI_API_KEY , etc.)
`--extension-policy safe balanced
`--repair-policy off suggest
--list-models [PATTERN]
List available models (optional fuzzy filter)
--list-providers
List canonical provider IDs, aliases, and auth env keys
--export <PATH>
Export session file to HTML

Additional high-leverage flags:

--no-migrations

to skip startup migration checks--explain-extension-policy

to print effective capability decisions and exit--explain-repair-policy

to print effective repair-policy resolution and exit

pi install <source> [-l|--local]    # Install a package source and add to settings
pi remove <source> [-l|--local]     # Remove a package source from settings
pi update [source]                 # Update all (or one) non-pinned packages
pi list                            # List user + project packages from settings

pi config                          # Show settings paths + precedence

More utility subcommands:

pi update-index
pi search "git"
pi info pi-search-agent

pi doctor
pi doctor --only sessions --format json
pi doctor --only swarm --format json
pi doctor ./path/to/extension --policy safe --fix

pi swarm-progress --input progress-slo-input.json --format json
pi swarm-progress --input progress-slo-input.json --since HEAD~1 --out-json progress-slo.json

pi migrate ~/.pi/agent/sessions --dry-run
pi migrate ~/.pi/agent/sessions

update-index

refreshes extension index metadata used bysearch

andinfo

.search

andinfo

let you discover and inspect extension metadata without leaving the CLI.doctor

checks config, directories, auth, shell setup, sessions, swarm coordination readiness, and extension compatibility.pi doctor --only swarm --format json

also reports cgroup CPU quota, cpuset size, NUMA topology, cgroup memory limits, target/tmp headroom, and recommended concurrency budgets before large multi-agent runs.swarm-progress

evaluates a normalized progress SLO snapshot and emits advisory JSON/text only; it does not mutate Beads, git, Agent Mail, RCH, validation broker slots, runpacks, or source files. Operator workflow, privacy boundaries, degraded Agent Mail/RCH interpretation, stale-Beads handling, and no-open-work convergence guidance lives indocs/swarm-operations-runbook.md#progress-slo-operator-workflow.migrate

validates or creates the v2 session sidecar format for faster resume on larger histories.

Pi reads configuration from ~/.pi/agent/settings.json

:

{
  "default_provider": "anthropic",
  "default_model": "claude-opus-4-5",
  "default_thinking_level": "medium",

  "compaction": {
    "enabled": true,
    "reserve_tokens": 8192,
    "keep_recent_tokens": 20000
  },

  "retry": {
    "enabled": true,
    "max_retries": 3,
    "base_delay_ms": 1000,
    "max_delay_ms": 30000
  },

  "images": {
    "auto_resize": true,
    "block_images": false
  },

  "terminal": {
    "show_images": true,
    "clear_on_shrink": false
  },

  "shell_path": "/bin/bash",
  "shell_command_prefix": "set -e"
}

Settings are resolved in priority order (first match wins):

CLI flags(--model

,--thinking

,--provider

, etc.)Environment variables(ANTHROPIC_API_KEY

,PI_CONFIG_PATH

, etc.)Project settings(.pi/settings.json

in the working directory)Global settings(~/.pi/agent/settings.json

)Built-in defaults

This means a CLI flag always overrides a settings.json

value, and a project-level setting overrides the global one.

Skills, prompt templates, themes, and extensions follow the same resolution order:

  • CLI-specified paths ( --skill

,--prompt-template

,--theme

,-e

) - Project directory ( .pi/skills/

,.pi/prompts/

,.pi/themes/

,.pi/extensions/

) - Global directory ( ~/.pi/agent/skills/

,~/.pi/agent/prompts/

, etc.) - Installed packages ( ~/.pi/agent/packages/

)

When multiple resources share the same name, the first occurrence wins. Collisions are logged as diagnostics.

Prompt template expansion supports positional arguments: $1

, $2

, $@

(all args), and slice syntax ${@:start}

, ${@:start:length}

. For example, a template invoked as /review src/main.rs --strict

receives src/main.rs

as $1

and --strict

as $2

.

Variable Description
ANTHROPIC_API_KEY
Anthropic API key
OPENAI_API_KEY
OpenAI API key
GOOGLE_API_KEY
Google Gemini API key
AZURE_OPENAI_API_KEY
Azure OpenAI API key
COHERE_API_KEY
Cohere API key
GROQ_API_KEY
Groq API key (OpenAI-compatible)
DEEPINFRA_API_KEY
DeepInfra API key (OpenAI-compatible)
CEREBRAS_API_KEY
Cerebras API key (OpenAI-compatible)
OPENROUTER_API_KEY
OpenRouter API key (OpenAI-compatible)
MISTRAL_API_KEY
Mistral API key (OpenAI-compatible)
MOONSHOT_API_KEY
Moonshot/Kimi API key (OpenAI-compatible)
DASHSCOPE_API_KEY
DashScope/Qwen API key (OpenAI-compatible)
DEEPSEEK_API_KEY
DeepSeek API key (OpenAI-compatible)
FIREWORKS_API_KEY
Fireworks API key (OpenAI-compatible)
TOGETHER_API_KEY
Together API key (OpenAI-compatible)
PERPLEXITY_API_KEY
Perplexity API key (OpenAI-compatible)
XAI_API_KEY
xAI API key (OpenAI-compatible)
PI_CONFIG_PATH
Custom config file path
PI_CODING_AGENT_DIR
Override the global config directory
PI_PACKAGE_DIR
Override the packages directory
PI_SESSIONS_DIR
Custom sessions directory
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           CLI (clap)                            β”‚
β”‚  β€’ Argument parsing    β€’ @file expansion    β€’ Subcommands       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          Agent Loop                             β”‚
β”‚  β€’ Message history     β€’ Tool iteration    β€’ Event callbacks    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                      β”‚                      β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Provider Layer  β”‚  β”‚  Tool Registry     β”‚  β”‚  Extension Mgr     β”‚
β”‚ β€’ Anthropic     β”‚  β”‚  β€’ read  β€’ bash    β”‚  β”‚  β€’ QuickJS JS/TS   β”‚
β”‚ β€’ OpenAI (Chat/ β”‚  β”‚  β€’ write β€’ grep    β”‚  β”‚  β€’ Native descriptorβ”‚
β”‚   Responses)    β”‚  β”‚  β€’ edit  β€’ find    β”‚  β”‚    runtime          β”‚
β”‚ β€’ Gemini/Cohere β”‚  β”‚  β€’ ls              β”‚  β”‚  β€’ Capability policyβ”‚
β”‚ β€’ Azure/Bedrock β”‚  β”‚  β€’ ext-registered  β”‚  β”‚  β€’ Node shims       β”‚
β”‚ β€’ Vertex/Copilotβ”‚  β”‚                    β”‚  β”‚  β€’ Event hooks      β”‚
β”‚ β€’ GitLab/Ext    β”‚  β”‚                    β”‚  β”‚  β€’ Runtime risk ctl β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                     β”‚                      β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Session Persistence                         β”‚
β”‚  β€’ JSONL format (v3)   β€’ Tree structure   β€’ Session index/cache  β”‚
β”‚  β€’ Per-project dirs    β€’ Default-enabled SQLite backend support β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Provider-count rule: Pi has 10 native provider implementation modules, counted as the Rust files under src/providers/

excluding mod.rs

. Those modules are anthropic

, openai

, openai_responses

, gemini

, cohere

, azure

, bedrock

, vertex

, copilot

, and gitlab

. User-visible provider IDs, aliases, OpenAI-compatible presets, and extension-provided streamSimple

providers are counted separately because several native modules expose multiple routes.

No unsafe code:#![forbid(unsafe_code)]

enforced project-wideStreaming-first: Custom SSE parser, no blocking on responses** Process tree management**:sysinfo

crate ensures no orphaned processesStructured errors:thiserror

with specific error types per componentSize-budgeted release profile: LTO + strip +opt-level = "z"

for budget-compliant shipping artifacts

This Rust port preserves Pi's user experience, but intentionally changes the runtime substrate. The original TypeScript Pi (pi-mono

, packages/coding-agent

) is built on Node.js + package-level abstractions. pi_agent_rust

moves those same behaviors onto asupersync

primitives so lifecycle guarantees are explicit in the runtime model.

Concern TypeScript Pi (pi-mono baseline) pi_agent_rust + asupersync
Runtime model
Node event loop + Promise/AbortSignal conventions RuntimeBuilder + explicit reactor and runtime handle
Async ownership
Task lifetimes coordinated by framework/library code Structured task ownership and explicit cross-thread channels (TUI/RPC bridging)
Cancellation semantics
Primarily API- and tool-layer conventions Runtime-aware cancellation checks + bounded timeout handling in tools
I/O capability shape
Ambient Node APIs + extension layer policies Capability-scoped context (AgentCx over asupersync::Cx ) and explicit hostcall policy
HTTP streaming
Provider/client dependent Purpose-built asupersync HTTP/TLS client feeding custom SSE parser
Deterministic test hooks
Conventional async test setup asupersync test/runtime hooks used widely in unit/integration tests

Why this is useful in practice:

More predictable failure behavior during aborts/timeouts because cancellation is checked in explicit loop boundaries and tool runners.Cleaner resource lifetimes because the runtime, timers, and I/O paths all share one concurrency substrate.Less hidden coupling because the main invariants live in Rust types/algorithms rather than spread across framework conventions.

These are the concrete invariants we rely on in this implementation:

Turn-scoped agent lifecycle- The main loop emits AgentStart

,TurnStart

,TurnEnd

, andAgentEnd

in a stable order. - Tool recursion is bounded by max_tool_iterations

(default50

) to avoid unbounded self-tool loops. - Benefit: stable event ordering for TUI/RPC consumers and predictable termination behavior.

  • The main loop emits

Abort and timeout behavior is explicit- Agent abort checks happen at turn boundaries and around tool execution. bash

timeout follows a clear escalation path: terminate process tree, grace period, then hard kill.- Benefit: fewer "hung" sessions and reduced orphan-process risk during aggressive tool use.

Session writes are crash-resilient- JSONL saves write to a temp file and persist atomically.

  • Session indexing uses SQLite WAL + lock file coordination for concurrent instances.

  • Benefit: better durability and resume reliability under multi-process usage.

Compaction is threshold-driven and boundary-aware- Trigger: estimated context tokens exceed context_window - reserve_tokens

. - Cut-point logic prefers user-turn boundaries and preserves recent context budget.

  • Benefit: compaction recovers context without collapsing near-term task continuity.

  • Trigger: estimated context tokens exceed

Capability policy is fail-closed and precedence-defined- Resolution order: per-extension deny -> global deny -> per-extension allow -> default caps -> mode fallback.

  • Benefit: policy outcomes are explainable, deterministic, and auditable.

Streaming parser tolerates real network chunking- SSE parser handles CR/LF variants, multi-line data:

fields, partial UTF-8 tails, and end-of-stream flush. - Benefit: incremental rendering remains robust across providers and network fragmentation.

  • SSE parser handles CR/LF variants, multi-line

The following asupersync

principles are reflected directly in pi_agent_rust

architecture:

Single async substrate: runtime, timers, fs, and HTTP/TLS all run on one coherent foundation.** Explicit context threading**:AgentCx

wrapsasupersync::Cx

at subsystem boundaries (agent/tools/session/rpc).Bounded operations over best-effort cleanup: timeout paths and compaction thresholds are parameterized and enforceable.** Determinism hooks for tests**: timer-driver aware sleeps and asupersync test helpers reduce nondeterministic flakiness.

Compared to the original TypeScript implementation, this shifts more correctness responsibility into the runtime and core algorithms themselves, instead of relying primarily on ecosystem conventions.

This is a second comparison pass focused on high-impact architectural deltas and rationale.

| Area | Original pi-mono (packages/coding-agent ) | pi_agent_rust | Why this divergence exists | |---|---|---|---| Distribution model | npm package (npm install -g @mariozechner/pi-coding-agent ) | Single Rust binary (pi ) | Remove Node runtime dependency and improve startup/deployment portability | Execution surfaces | Interactive + print + JSON mode + RPC + SDK | Interactive + print + JSON mode + RPC + Rust SDK | Rust SDK provides idiomatic companion API for embedding Pi programmatically (documented in docs/sdk.md ) | Default built-in tool posture | Defaults to read/write/edit/bash (others available) | Eight built-ins treated as first-class (read/write/edit/bash/grep/find/ls/hashline_edit ) | Keep common code-navigation, shell, and hashline-anchored edit workflows available without extra configuration | Extension trust model | Extension/package model documented as full system access | Embedded runtime with capability-gated hostcalls and policy profiles | Reduce ambient authority and make extension behavior auditable/deny-by-default | Session architecture emphasis | JSONL tree session model and branch navigation | JSONL v3 tree + explicit session index (SQLite sidecar) + default-enabled SQLite session backend support | Faster resume/lookups at scale and safer multi-instance coordination | Streaming transport stack | Node runtime networking stack | Purpose-built HTTP/TLS client + custom SSE parser on asupersync | Tighter control over chunking, parsing, and failure handling in long streams | Cancellation/timeout mechanics | Platform/event-loop cancellation conventions | Explicit abort signaling, bounded tool iterations, process-tree termination | Minimize hangs/orphans and make stop behavior deterministic under load | Runtime context model | Framework-level conventions and extension APIs | Explicit AgentCx /asupersync::Cx capability-scoped context threading | Make effect boundaries and testability first-class architectural constraints |

Practical consequence of these deltas:

  • Extension/package workflows are compatible across both implementations.
  • The goal is functional equivalence to pi-mono with Rust-idiomatic patterns and performance improvements.
  • The Rust SDK provides a companion API that delivers equivalent capabilities without requiring TypeScript-specific adaptation patterns. docs/parity-certification.json

tracks functional parity progress and certification status.

This section compares concrete implementation mechanics for equivalent high-level behavior.

Algorithm pi-mono baseline mechanism Rust implementation mechanism Why the Rust variant exists
Session context rebuild after compaction
buildSessionContext() emits compaction summary, then messages from firstKeptEntryId (pre-compaction path), then post-compaction entries
to_messages_for_current_path() uses the same ordering and adds a fallback if first_kept_entry_id is missing
Avoid silent context loss when compaction anchors are orphaned/corrupted
JSONL persistence
Incremental append (appendFileSync ) plus full rewrite (writeFileSync ) for migrations/rewrites
Save via temp file + atomic persist/replace Keep on-disk session state crash-resilient during save operations
Session discovery/resume
Directory/file scan and mtime sorting of JSONL files SQLite session index sidecar + WAL + lock file + staleness-triggered full reindex Bound resume lookup cost and coordinate concurrent processes
Compaction token accounting
Uses assistant usage (totalTokens else input+output+cacheRead+cacheWrite ) plus heuristic trailing estimates
Uses assistant usage (total_tokens else input+output ) plus heuristic trailing estimates; fixed image token estimate
Keep accounting stable across providers with uneven cache-token reporting while staying conservative
Cut-point + split-turn handling
Valid cut points exclude tool results; split turns are summarized as history + turn-prefix context Same cut-point class and split-turn strategy, implemented in Rust entry/message model Preserve tool-call/result adjacency and turn coherence under budget pressure
Bash timeout/process cleanup
Timeout/abort kills process tree (killProcessTree ) and returns tail-truncated output
Timeout escalation (TERM then grace then KILL ) + process-tree walk + shell exit trap + tail truncation
Enforce bounded cleanup and reduce descendant-process leaks from background jobs
Streaming event decoding
Transport semantics are exposed (sse /websocket /auto ); parser details are runtime-internal
Explicit SSE parser with BOM stripping, CR/LF normalization, UTF-8 tail buffering, and flush-on-end Make byte-to-event behavior deterministic and provider-SDK-independent

The sections above compare mechanics. This section calls out concrete features present in this Rust port that are not part of the pi-mono baseline implementation model.

Rust-port feature Why it is useful/compelling
(pi doctor diagnostics commandtext /json /markdown , --only , --fix , swarm preflight, extension compatibility checks)
Gives actionable environment + compatibility diagnostics, supports CI gating (non-zero on failures), can auto-fix safe issues like missing dirs/permissions, and reports read-only multi-agent readiness before swarm work
Capability-gated extension policy profiles (safe / balanced / permissive ) with per-extension overrides
Lets operators run shared extensions with explicit capability boundaries instead of ambient full-system access
Secret-aware extension env filtering (pi.env() blocklist for keys/tokens/secrets)
Reduces accidental credential exposure from extension code paths
Per-extension trust lifecycle + kill-switch audit trail (pending /acknowledged /trusted /killed , kill_switch , lift_kill_switch )
Supports immediate containment, explicit operator provenance, and controlled re-entry after review
Hostcall compatibility-lane emergency controls (global/per-extension forced-compat switches + reason codes)
Gives operators a deterministic rollback path for fast-lane incidents without losing extension availability
Runtime risk controller for extension hostcalls (configurable, fail-closed by default)
Adds another enforcement layer beyond static policy for suspicious runtime behavior in extension call flows
Argument-aware runtime risk scoring for shell paths (dcg_rule_hit , dcg_heredoc_hit , heredoc AST inspection across Bash/Python/JS/TS/Ruby)
Detects destructive intent hidden in multiline scripts and wrapper commands before hostcall execution
Tamper-evident runtime risk ledger tooling (`ext_runtime_risk_ledger verify
replay
Unified incident evidence bundle export (risk ledger, security alerts, hostcall telemetry, exec mediation, secret-broker events)
Incident response can triage from one structured artifact set instead of stitching ad-hoc logs
Deterministic hostcall reactor mesh with optional NUMA slab pool (shard affinity, global-order drain, bounded SPSC lanes, telemetry)
Keeps extension dispatch predictable under load and surfaces queue/backpressure behavior for tuning
Warm isolate pool + startup prewarm handoff
Moves JS runtime preparation off the first interactive turn and reuses warmed state safely between runs
Extension preflight static analysis (imports/forbidden-pattern scan with policy-aware hints)
Catches risky extension patterns before runtime execution
Node/Bun-compatible extension runtime without Node/Bun dependency (embedded QuickJS + shims)
Runs legacy extension workflows in a single native binary deployment model
Extension compatibility scanner + conformance harness
Makes extension support measurable and auditable instead of anecdotal
SQLite session index sidecar (WAL + lock + stale reindex path)
Gives fast session resume/list operations at scale without scanning every JSONL file on each query
Session Store V2 rollback and migration ledger (segmented log + checkpoints + rollback events)
Long-session recovery can unwind to a known checkpoint with explicit migration/rollback provenance
Default-enabled SQLite session storage support (sqlite-sessions feature)
Supports deployments that want database-backed session persistence in addition to JSONL; disable with --no-default-features when building a minimal binary
Crash-resilient session save path (temp file + atomic persist)
Improves session-file durability during writes and reduces partial-write failure modes
Unified hostcall dispatcher with typed taxonomy mapping (timeout / denied / io / invalid_request / internal )
Produces consistent extension/runtime error semantics and easier client handling
Fail-closed evidence-lineage gates (run_id /correlation_id + cross-artifact lineage checks)
Rejects stale or cherry-picked conformance/perf artifacts at release-gate time
Structured auth diagnostics with stable machine codes
Improves troubleshooting and operational visibility without leaking sensitive credential material

Pi deliberately uses advanced math where it improves runtime behavior or benchmark confidence. The goal is not β€œfancy formulas in docs”; it is safer policy decisions, faster recovery from workload shifts, and more trustworthy performance attribution.

In the extension dispatcher, Pi combines CUSUM and Bayesian online change-point detection to detect load-regime changes early (for example when hostcall traffic suddenly spikes or stalls).

Intuition: CUSUM catches persistent drift; BOCPD catches sudden regime changes without brittle fixed thresholds.

Pi tracks nonconformity scores (absolute residuals from the running mean) and treats out-of-interval events as anomalies.

Intuition: thresholds adapt from recent behavior instead of hard-coding one static latency cutoff.

Pi’s safety envelope includes a PAC-Bayes-kl bound over extension outcomes, and can veto aggressive optimization when the bound is too high.

Intuition: this gives an explicit uncertainty-aware ceiling on true error risk before allowing more aggressive runtime behavior.

Before approving policy moves, Pi evaluates candidate behavior from trace data:

Intuition: Pi fails closed if sample support is weak, uncertainty is high, or estimated regret is above threshold.

The VOI planner prioritizes probes that provide the most expected learning under a strict overhead budget.

Intuition: run only the experiments that are likely to change decisions; skip stale or low-value probes.

For phase-1 matrix benchmarking, Pi computes stage attribution weighted by realistic workload size (session_messages

) and reports confidence intervals.

\frac{\sum_i w_i,m_{i,s}}{\sum_i w_i,t_i}\cdot 100, \quad w_i=\text{session_messages}_i $$

Intuition: prioritize what dominates real end-to-end latency, not just isolated microbench hotspots.

Pi also includes an online tuner path for batch/time-slice controls with explicit rollback behavior:

\mathrm{clip}!\left(\tau_t - \eta\nabla_{\tau}\mathcal{L}t,;\tau{\min},\tau_{\max}\right) $$

Intuition: the system adapts continuously, but if instantaneous loss exceeds a rollback threshold it immediately returns to a safer profile.

Technique Where in Pi Why it helps
CUSUM + BOCPD Extension dispatcher regime detector Detects traffic regime shifts early and robustly
Conformal intervals Safety envelope Adaptive anomaly gating without static magic numbers
PAC-Bayes bound Safety envelope veto path Fails closed when uncertainty/risk is too high
IPS/WIS/DR + ESS Off-policy evaluator Approves policy changes only with adequate support
VOI planning Experiment scheduler Uses overhead budget on highest-value probes
Weighted attribution + CI Phase-1 perf matrix reports Ranks optimization work by realistic user impact
OCO + regret rollback Runtime controller Adapts under load while bounding unsafe drift

The SSE (Server-Sent Events) parser is a custom implementation that handles Anthropic's streaming response format. Unlike library-based approaches, the parser operates as a state machine that processes bytes incrementally:

Bytes β†’ Line Accumulator β†’ Event Parser β†’ Typed StreamEvent

Key characteristics:

Property Implementation
Buffering
Zero-copy where possible; lines accumulated only when incomplete
Event types
12 distinct variants: MessageStart, ContentBlockStart, ContentBlockDelta, ContentBlockStop, MessageDelta, MessageStop, Ping, Error, and thinking-specific events
Error recovery
Malformed events logged but don't crash the stream
Memory
Fixed-size rolling buffer prevents unbounded growth

The parser handles edge cases like:

  • Multi-line data:

fields (concatenated with newlines) - Events split across TCP packet boundaries

  • The event:

field appearing before or afterdata:

  • CRLF and LF line endings interchangeably

Large outputs from tools (file reads, command output, grep results) must be truncated to avoid exhausting the LLM's context window. The truncation algorithm preserves usefulness while staying within limits:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Original Content              β”‚
β”‚         (potentially huge)              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  HEAD: First N/2 lines                  β”‚
β”‚  ─────────────────────────              β”‚
β”‚  [... X lines truncated ...]            β”‚
β”‚  ─────────────────────────              β”‚
β”‚  TAIL: Last N/2 lines                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Constants:

Limit Value Rationale
MAX_LINES
2000 Balances context usage vs. completeness
MAX_BYTES
1MB Prevents binary file accidents
GREP_MAX_LINE_LENGTH
500 chars Truncates minified code

The algorithm:

  • Splits content into lines
  • If line count exceeds MAX_LINES

, takes first 1000 and last 1000 - Inserts a marker showing how many lines were omitted

  • If byte count still exceeds MAX_BYTES

, applies byte-level truncation - Returns metadata indicating truncation occurred, enabling the LLM to request specific ranges

The bash

tool must handle runaway processes, infinite loops, and fork bombs without leaving orphans. The implementation uses the sysinfo

crate to walk the process tree:

// Pseudocode for process cleanup
fn kill_process_tree(root_pid: Pid) {
    let system = System::new();
    let children = find_all_descendants(root_pid, &system);

    // Kill children first (deepest first), then parent
    for child in children.iter().rev() {
        kill(child, SIGKILL);
    }
    kill(root_pid, SIGKILL);
}

Timeout behavior:

  • Command starts with configurable timeout (default 120s)
  • Output streams to a rolling buffer in real-time
  • On timeout: SIGTERM sent, 5s grace period, then SIGKILL
  • Process tree walked and all descendants killed
  • Exit code set to indicate timeout vs. normal termination

To avoid orphaned background jobs (e.g. cmd &

), the bash script installs an EXIT

trap that waits for any remaining child processes and then exits with the original command's status.

This prevents the common failure mode where killing a shell leaves its children running.

Sessions use a tree structure rather than a flat list, enabling conversation branching (useful when exploring different approaches):

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚ Message β”‚ (root)
                    β”‚   #1    β”‚
                    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                         β”‚
                    β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”
                    β”‚ Message β”‚
                    β”‚   #2    β”‚
                    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                         β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                     β”‚
         β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”
         β”‚ Message β”‚          β”‚ Message β”‚ (branch)
         β”‚   #3    β”‚          β”‚   #3b   β”‚
         β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
              β”‚                    β”‚
         β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”
         β”‚ Message β”‚          β”‚ Message β”‚
         β”‚   #4    β”‚          β”‚   #4b   β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

JSONL format (v3):

Each line is a self-contained JSON object with a type

discriminator:

{"type":"session","version":3,"cwd":"/project","created":"2024-01-15T10:30:00Z"}
{"type":"message","id":"a1b2c3d4","parent":"root","role":"user","content":[...]}
{"type":"message","id":"e5f6g7h8","parent":"a1b2c3d4","role":"assistant","content":[...]}
{"type":"model_change","id":"i9j0k1l2","parent":"e5f6g7h8","model":"claude-sonnet-4-20250514"}

The parent

field creates the tree. Replaying a session walks the tree from root to the current leaf. Branching creates a new message with a different parent

than the previous continuation.

The Provider

trait abstracts over different LLM backends:

#[async_trait]
pub trait Provider: Send + Sync {
    fn name(&self) -> &str;
    fn models(&self) -> &[Model];

    async fn stream(
        &self,
        context: &Context,
        options: &StreamOptions,
    ) -> Result<impl Stream<Item = Result<StreamEvent>>>;
}

Context structure:

pub struct Context {
    pub system: Option<String>,      // System prompt
    pub messages: Vec<Message>,       // Conversation history
    pub tools: Vec<ToolDef>,          // Available tools with JSON schemas
}

StreamOptions:

pub struct StreamOptions {
    pub model: String,
    pub max_tokens: u32,
    pub temperature: Option<f32>,
    pub thinking: Option<ThinkingConfig>,  // Extended thinking settings
    pub stop_sequences: Vec<String>,
}

This design allows adding new providers (OpenAI, Gemini) without modifying the agent loop. Each provider translates the common types to its wire format and emits a unified StreamEvent

stream.

Long conversations eventually exceed the model's context window. Pi's compaction algorithm reclaims space by summarizing older messages while preserving recent context.

The algorithm runs automatically after each agent turn when estimated token usage exceeds context_window - reserve_tokens

:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Full Conversation                         β”‚
β”‚  msg1 β†’ msg2 β†’ msg3 β†’ ... β†’ msgN-5 β†’ msgN-4 β†’ ... β†’ msgN   β”‚
β”‚  β”œβ”€β”€β”€β”€ older messages ────── β”œβ”€β”€β”€ recent messages ─────────── β”‚
β”‚                                                              β”‚
β”‚  Step 1: Find cut point at a valid turn boundary             β”‚
β”‚  Step 2: LLM summarizes msgs 1..N-5 into compact paragraph  β”‚
β”‚  Step 3: Store Compaction entry in session JSONL             β”‚
β”‚  Step 4: Next agent call uses [summary] + msgs N-4..N       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Token estimation uses a conservative chars Γ· 4

heuristic for text and a flat 1,200 tokens per image. When an assistant message includes a usage

field from the API, that measured value takes precedence over the heuristic.

Cut point selection prefers boundaries between complete user-assistant turns. If the budget forces a mid-turn cut, the algorithm includes prefix messages from the split turn so the model retains context about what was being discussed at the boundary.

File operation tracking extracts read

, write

, and edit

tool calls from the messages being summarized. The compaction prompt includes these paths so the summary preserves awareness of which files were examined or modified:

<read-files>
src/main.rs
src/config.rs
</read-files>

<modified-files>
src/auth.rs
</modified-files>

Configurable parameters:

Parameter Default Purpose
reserve_tokens
8% of context window Safety margin for response generation
keep_recent_tokens
10% of context window Minimum recent context preserved

Compaction can also be triggered manually with /compact

in interactive mode or the compact

RPC command.

Pi routes model requests through a provider factory that resolves the correct backend implementation from a (provider, model, api)

tuple.

Resolution flow:

User specifies --provider openai --model gpt-4o
               β”‚
               β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Provider Metadata Table  β”‚  Maps "openai" β†’ canonical ID,
  β”‚                           β”‚  determines API type (Completions
  β”‚                           β”‚  vs Responses vs custom)
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  URL Normalization         β”‚  Appends /chat/completions,
  β”‚                            β”‚  /responses, or /chat depending
  β”‚                            β”‚  on detected API type
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Compat Config             β”‚  Applies per-model overrides:
  β”‚                            β”‚  system_role_name, max_tokens
  β”‚                            β”‚  field name, feature flags
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Provider Instance         β”‚  Anthropic | OpenAI | Gemini
  β”‚                            β”‚  Cohere | Azure | Bedrock | ...
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

** models.json overrides**: Users can define custom providers in

~/.pi/agent/models.json

or .pi/models.json

. Each entry specifies a model ID, base URL, API type, and optional compat flags, letting you route to self-hosted models, proxies, or providers that Pi does not natively support.Compat config handles the differences between OpenAI-compatible APIs:

Override Example Purpose
system_role_name
"developer"
o1 models use "developer" instead of "system"
max_tokens_field
"max_completion_tokens"
Some models require a different field name
supports_tools
false
Suppress tool definitions for models that reject them
supports_streaming
false
Fall back to non-streaming for incompatible endpoints
custom_headers
{"X-Custom": "val"}
Per-provider header injection

Fuzzy matching: When a provider name doesn't match any known provider, Pi computes edit distance against all registered names and suggests the closest match in the error message.

Extensions run in an embedded QuickJS runtime (rquickjs

crate) and communicate with Pi through a structured hostcall protocol. This is the mechanism that lets JavaScript code invoke Pi's built-in tools, make HTTP requests, and interact with the session, all without direct OS access.

Execution model:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ QuickJS VM ───────────────────┐
β”‚                                                   β”‚
β”‚  extension.js calls:                              β”‚
β”‚    pi.tool("read", {path: "src/main.rs"})         β”‚
β”‚      β”‚                                            β”‚
β”‚      β–Ό                                            β”‚
β”‚    enqueue HostcallRequest {                      β”‚
β”‚      call_id: "hc-0042",                          β”‚
β”‚      kind: Tool { name: "read" },                 β”‚
β”‚      payload: { path: "src/main.rs" },            β”‚
β”‚    }                                              β”‚
β”‚      β”‚                                            β”‚
β”‚      β–Ό                                            β”‚
β”‚    return Promise (resolve/reject stored in map)  β”‚
β”‚                                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚
    drain_hostcall_requests()
                         β”‚
                         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ ExtensionDispatcher ──────────────┐
β”‚                                                   β”‚
β”‚  1. Check capability policy:                      β”‚
β”‚     read tool β†’ requires "read" capability        β”‚
β”‚     β†’ Policy says: Allow / Deny / Prompt          β”‚
β”‚                                                   β”‚
β”‚  2. If allowed β†’ dispatch to ToolRegistry         β”‚
β”‚     β†’ Execute read tool                           β”‚
β”‚     β†’ Get ToolOutput                              β”‚
β”‚                                                   β”‚
β”‚  3. complete_hostcall("hc-0042", Ok(result))      β”‚
β”‚     β†’ Resolves the Promise in QuickJS             β”‚
β”‚                                                   β”‚
β”‚  4. runtime.tick()                                β”‚
β”‚     β†’ Drains Promise .then() chains               β”‚
β”‚     β†’ Extension JS continues execution            β”‚
β”‚                                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Capability mapping: Each hostcall kind maps to a required capability:

Hostcall Required Capability Dangerous?
pi.tool("read", ...)
read
No
pi.tool("write", ...)
write
No
pi.tool("bash", ...)
exec
Yes
pi.http(request)
http
No
pi.exec(cmd, args)
exec
Yes
pi.env(key)
env
Yes
pi.session(op, ...)
session
No
pi.ui(op, ...)
ui
No
pi.log(entry)
log
No (always allowed)

Deduplication: Each hostcall's parameters are canonicalized (object keys sorted, structure normalized) and SHA-256 hashed. Identical requests within a short window can be deduplicated to avoid redundant tool executions.

Fast lane vs compatibility lane: Pi has two execution lanes for hostcalls:

Fast lane is used when the call shape matches known safe patterns (for example commontool

andsession

operations). This avoids extra allocation and parsing work.Compatibility lane is the fallback for uncommon or partially-specified calls.- Both lanes still enforce the same capability policy and permission checks.

  • Operators can force compatibility-lane routing globally or per extension as an emergency control path.

For observability, each call is tagged with a stable lane key (for example tool|tool.read|filesystem

or tool|fallback|filesystem

) so latency and failure trends can be grouped consistently.

Built-in consistency guard (shadow dual execution): Pi can sample a small subset of read-only hostcalls, execute them through both lanes, and compare canonical output fingerprints. If divergence crosses a configured budget, Pi automatically backs off the fast lane for a period. This gives performance wins without silently changing behavior.

Adaptive dispatch mode under load: Pi can switch between:

sequential_fast_path

for simpler/low-contention workloadsinterleaved_batching

when contention and queue pressure rise

Mode changes are gated by sample coverage and risk checks, so Pi does not switch based on thin or cherry-picked evidence.

Runtime telemetry for debugging and tuning: Pi records structured hostcall telemetry (pi.ext.hostcall_telemetry.v1

) with lane choice, fallback reason, dispatch latency share, marshalling path, and optimization hit/miss fields. This is used by perf reports and reliability diagnostics.

Auto-repair pipeline: When an extension fails to load or produces runtime errors, Pi's repair system can automatically fix common issues:

Repair Mode Behavior
Off
No repairs
Suggest
Log suggestions, don't apply
AutoSafe (default)
Apply provably safe fixes (missing file paths, asset references)
AutoStrict
Apply aggressive heuristic fixes (pattern-based transforms)

Compatibility scanner: Before , Pi statically analyzes extension source code for imports, require()

calls, and forbidden patterns (eval

, Function()

, process.binding

, dlopen

). The scan produces a capability evidence ledger that informs policy decisions.

Environment variable filtering: Extensions calling pi.env()

hit a blocklist that denies access to API keys, credentials, tokens, and private keys. The filter blocks exact matches (ANTHROPIC_API_KEY

, AWS_SECRET_ACCESS_KEY

), suffix patterns (*_API_KEY

, *_SECRET

, *_TOKEN

), and prefix patterns (AWS_SECRET_*

, AWS_SESSION_*

). Only PI_*

variables are unconditionally allowed.

Trust lifecycle and kill switch: Extension trust state is tracked explicitly (pending

, acknowledged

, trusted

, killed

). A kill switch demotes an extension to killed

, quarantines it in the runtime risk controller, emits a critical alert, and writes an audit record. Lifting the switch requires an explicit operator action and moves the extension back to acknowledged

.

The extension runtime includes a few small decision engines so behavior stays stable as workload patterns change:

Value-of-information planner (VOI): Ranks candidate probes by "expected learning per millisecond" and picks the best set under a strict overhead budget. Stale or low-value candidates are skipped with explicit reasons.Shard load controller: Adjusts routing weights, batch budgets, and backoff/help factors based on queue pressure, latency, and starvation risk. Damping and oscillation guards prevent overreaction.Policy safety evaluator: Replays historical samples with multiple estimators and only approves a policy when sample support is strong, uncertainty is low, and predicted regret stays within limit.

These pieces are intentionally conservative: if confidence is weak, Pi holds steady instead of making an aggressive switch.

The interactive mode uses the Elm Architecture (Model-Update-View) via the charmed_rust

library family, which is a Rust port of Go's Bubble Tea framework.

Component stack:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 Terminal (crossterm)                β”‚
β”‚  Raw mode β”‚ Alt screen β”‚ Keyboard/Mouse events      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚             bubbletea Program Loop                  β”‚
β”‚  Init() β†’ Update(Msg) β†’ View() β†’ render cycle      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  PiApp (Model)                      β”‚
β”‚                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  TextArea    β”‚ β”‚  Viewport    β”‚ β”‚  Spinner     β”‚  β”‚
β”‚  β”‚  (editor)    β”‚ β”‚  (convo)     β”‚ β”‚  (status)    β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚           Overlay Stack                      β”‚    β”‚
β”‚  β”‚  Model Selector β”‚ Session Picker β”‚ /tree     β”‚    β”‚
β”‚  β”‚  Settings UI    β”‚ Theme Picker   β”‚ Branches  β”‚    β”‚
β”‚  β”‚  Capability Prompt (extension UI)            β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
              async channels (mpsc)
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚             Agent Async Task                        β”‚
β”‚  Runs on asupersync runtime                         β”‚
β”‚  Streams provider responses                         β”‚
β”‚  Executes tools                                     β”‚
β”‚  Sends PiMsg events back to TUI thread              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The async/sync bridge: The agent runs on the asupersync

async runtime in a separate thread. It communicates with the bubbletea UI thread through mpsc

channels. Each streaming event (text delta, tool start, tool update, agent done) becomes a PiMsg

variant delivered to PiApp::update()

, keeping the UI responsive during API streaming and tool execution.

Viewport scrolling: The conversation viewport tracks whether the user is at the bottom. When new content arrives and the user hasn't scrolled up, the viewport auto-follows the stream tail. Scrolling up disables auto-follow; pressing End

or typing a new message re-enables it.

Overlay system: Modal UIs (model selector, session picker, branch navigator, extension capability prompts) stack on top of the main conversation view. Each overlay captures keyboard input until dismissed. Only the topmost active overlay receives events.

Slash commands available in the interactive editor:

Command Action
/help
Show available commands and keybindings
/model or Ctrl+L
Open model selector with fuzzy search
Ctrl+P / Ctrl+Shift+P
Cycle scoped models forward/backward
/tree
Browse and fork the conversation tree
/clear
Clear conversation and start fresh
/compact
Trigger manual compaction
/thinking <level>
Change thinking level mid-conversation
/share
Export session to GitHub Gist
/exit or Ctrl+C
Exit Pi

The RPC mode (pi --mode rpc

) exposes a line-delimited JSON protocol over stdin/stdout for programmatic integration. Each line is a self-contained JSON object.

Client β†’ Pi (stdin):

{"type": "prompt", "message": "Explain this function", "id": "req-001"}
{"type": "steer", "message": "Focus on error handling"}
{"type": "follow_up", "message": "Now add tests"}
{"type": "abort"}
{"type": "get_state"}
{"type": "compact", "reserveTokens": 8192, "keepRecentTokens": 20000}

Pi β†’ Client (stdout):

{"type": "agent_start", "sessionId": "..."}
{"type": "message_update", "message": {...}, "assistantMessageEvent": {"type": "text_delta", "delta": "The function", "contentIndex": 0}}
{"type": "tool_execution_start", "toolCallId": "...", "toolName": "read", "args": {}}
{"type": "tool_execution_end", "toolCallId": "...", "toolName": "read", "result": {}, "isError": false}
{"type": "agent_end", "sessionId": "...", "messages": [...]}
{"type": "response", "id": "req-001", "command": "prompt", "success": true, "data": {"status": "ok"}}

I/O architecture: Two dedicated threads handle stdin reading and stdout writing, bridged to the async agent runtime via channels. The stdin thread retries on transient errors to prevent dropped input. The stdout thread flushes after every line to prevent buffering delays.

Message queuing: While the agent is streaming a response, incoming messages are routed to one of two queues:

Queue Behavior Use Case
Steering
Interrupts current response; processed on next turn Course corrections
Follow-up
Queued until current response completes Sequential instructions

Queue modes (All

or OneAtATime

) control whether multiple queued messages are batched into a single turn or processed individually.

Extension UI over RPC: When an extension requests user input (capability prompt, selection dialog), Pi emits an extension_ui_request

event. The client renders the prompt in its own UI and responds with an extension_ui_response

message. IDE extensions can then present native UI for capability decisions instead of falling back to terminal prompts.

Session resume (pi -c

or pi -r

) needs to find the most recent session for the current project without scanning every JSONL file on disk. Pi maintains a SQLite index (session-index.sqlite

) that provides constant-time lookups.

Schema:

CREATE TABLE sessions (
    path            TEXT PRIMARY KEY,
    id              TEXT NOT NULL,
    cwd             TEXT NOT NULL,
    timestamp       TEXT NOT NULL,
    message_count   INTEGER NOT NULL,
    last_modified   INTEGER NOT NULL,
    size_bytes      INTEGER NOT NULL,
    name            TEXT
);

Update lifecycle:

  • After saving a session JSONL file, Pi upserts its metadata into the index pi -c

queriesWHERE cwd = ? ORDER BY last_modified DESC LIMIT 1

pi -r

queries the same table and presents a picker sorted by recency

Concurrency: A file-based lock (session-index.lock

) serializes writes from concurrent Pi instances. Reads use WAL mode for non-blocking access.

Staleness-based reindexing: If the index is older than a configurable threshold, Pi runs a full re-scan of the sessions directory to catch files created by other instances or manual edits. The re-scan keeps the index accurate without a centralized daemon.

Pi also supports a v2 sidecar store next to JSONL sessions for faster resume and stronger corruption checks on long histories.

What it adds:

  • Segmented append log files (instead of one ever-growing JSONL file)
  • Offset index rows for direct seeks and fast tail reads
  • Periodic checkpoints and a manifest snapshot
  • Migration ledger entries for auditability
  • Checkpoint-based rollback path with explicit rollback event logging

How resume works:

  • If a v2 sidecar exists and is fresh, Pi opens from the sidecar index + segments.
  • If sidecar data is stale relative to the source JSONL, Pi falls back to JSONL parsing.
  • If index data is missing/corrupt but segments are valid, Pi rebuilds the index.

Integrity strategy:

  • Segment frames carry payload and chain hashes.
  • Index rows store byte offsets plus CRC32C checksums.
  • Validation checks offset bounds, checksum matches, and frame/index alignment before trusting the sidecar.
  • Truncated trailing frames are recoverable during rebuild; non-EOF frame corruption fails closed instead of silently dropping data.

CLI support:

pi migrate <path> --dry-run

validates migration without writing.pi migrate <path>

performs JSONL-to-v2 migration and verifies parity.

Beyond simple API keys, Pi supports OAuth, AWS credential chains, service key exchange, and bearer-token auth. Credentials are stored in ~/.pi/agent/auth.json

with file-locked access to prevent corruption from concurrent instances. Stored API keys can be literal strings, $ENV:VAR_NAME

references, or $CMD:shell command

/ $COMMAND:shell command

sources that resolve trimmed stdout at request time.

Mechanism Providers Details
API Key
Anthropic, OpenAI, Gemini, Cohere, and many OpenAI-compatible providers Static key via env var or settings
OAuth
Anthropic, OpenAI Codex, Google Gemini CLI, Google Antigravity, Kimi for Coding, GitHub Copilot, GitLab, and extension-defined OAuth providers PKCE/state-validated flow with automatic refresh; Kimi uses device flow
AWS Credentials
Bedrock Access key + secret + optional session token; region-aware
Service Key
SAP AI Core Client ID/secret exchange for bearer token
Bearer Token
Custom providers Static token in auth storage

OAuth token lifecycle:

  • User runs pi

with an OAuth-configured provider - Pi checks auth.json

for an existing token - If missing: opens browser to authorization URL, user authenticates, Pi receives authorization code, exchanges it for access + refresh tokens, stores both with expiry timestamp

  • If expired but refresh token valid: exchanges refresh token for new access token, updates auth.json

  • Bearer token attached to API requests

Google CLI-style OAuth providers carry project metadata with the token payload. Pi preserves and refreshes that payload and can resolve project IDs from GOOGLE_CLOUD_PROJECT

or local gcloud

config when needed.

Credential status reporting: pi config

shows the status of each configured provider's credentials: Missing

, ApiKey

, OAuthValid

(with time until expiry), OAuthExpired

(with time since expiry), AwsCredentials

, or BearerToken

.

Diagnostic codes: Auth failures produce specific diagnostic codes (MissingApiKey

, InvalidApiKey

, QuotaExceeded

, OAuthTokenRefreshFailed

, MissingAzureDeployment

, MissingRegion

, etc.) with context-specific error hints rather than generic messages.

Read file contents (optionally images):

Input: { "path": "src/main.rs", "offset": 10, "limit": 50 }
  • Supports images (jpg, png, gif, webp) with optional auto-resize
  • Streams file bytes in chunks with hard size limits to reduce peak memory usage
  • Applies defensive image decode limits to block decompression-bomb/OOM inputs
  • Truncates at 2000 lines or 1MB
  • Returns continuation hint if truncated

Execute shell commands with timeout and output capture:

Input: { "command": "cargo test", "timeout": 120 }
  • Default 120s timeout, configurable per-call
  • Set timeout: 0

to disable the default timeout - Process tree cleanup on timeout (kills children)

  • Rolling buffer for real-time output
  • Full output saved to temp file if truncated

Surgical string replacement:

Input: { "path": "src/lib.rs", "old": "fn foo()", "new": "fn bar()" }
  • Exact string matching (no regex)
  • Fails if old string not found or ambiguous
  • Returns diff preview

Search file contents:

Input: { "pattern": "TODO", "path": "src/", "context": 2, "limit": 100 }
  • Regex patterns supported
  • Context lines before/after matches
  • Respects .gitignore

Discover files by pattern:

Input: { "pattern": "*.rs", "path": "src/", "limit": 1000 }
  • Glob patterns via fd

  • Sorted by modification time

  • Respects .gitignore

List directory contents:

Input: { "path": "src/", "limit": 500 }
  • Alphabetically sorted

  • Directories marked with trailing /

  • Truncates at limit

CLI tools have different performance requirements than servers or GUI applications. The critical metric is time-to-first-interaction: how quickly can the user start typing after invoking the command?

── more in #ai-tools 4 stories Β· sorted by recency
── more on @pi agent 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/pi-rust-high-perform…] indexed:0 read:53min 2026-07-07 Β· β€”