# rpi — a Rust-native coding-agent runtime
[](https://crates.io/crates/rpi-cli)
[](https://crates.io/crates/rpi-cli)
[](https://docs.rs/rpi-cli)
[](#license)
[](#install)
[](https://github.com/bigfish1913/pi-rust/actions/workflows/ci.yml)
[](https://github.com/bigfish1913/pi-rust/stargazers)
[](https://github.com/bigfish1913/pi-rust/releases/latest)
`rpi` is a library-first coding-agent runtime written in Rust, plus a terminal
agent built on top of it. Nine composable crates span provider adapters, a
durable crash-resumable agent loop, a terminal UI, and a stable plugin ABI — so
the same code works as an embedded SDK or as a ready-to-run `rpi` command.
rpi began as a Rust reimplementation of the [Pi TypeScript SDK](https://github.com/earendil-works/pi)
by Mario Zechner. It now includes its own Rust-native plugin ABI and execution
infrastructure. See [Acknowledgements](#acknowledgements) and the repository's
[NOTICE](https://github.com/bigfish1913/pi-rust/blob/main/NOTICE) for upstream attribution.
Website: <https://rpi.laofu.online/> · Docs: <https://rpi.laofu.online/docs.html>

<sub>Interactive TUI. See [`docs/guides/user-guide.md`](docs/guides/user-guide.md) for the full command surface.</sub>

<sub>The agent loop and a real `write` tool round-trip, recorded with no API key and no network — the same path the tests take. Source of truth is [`demo/sdk.tape`](demo/sdk.tape); regenerate with `task demo`.</sub>
## Three ways to use it
| A working terminal coding agent | nothing | `cargo install rpi-cli` |
| Your own agent inside your process | `rpi-agent` (+ `rpi-ai`, `rpi-tools`) | [`examples/minimal`](examples/minimal) |
| A tool/provider that extends every session | `rpi-plugin-sdk` | [`examples/plugin-stub`](examples/plugin-stub) |
The three share one implementation. Build your tools once, debug them inside an
embedded agent, and ship the same code as a `cdylib` plugin that the global `rpi`
loads. See [`docs/agent/project-structure.md`](docs/agent/project-structure.md) for the recommended
project layout.
## Install
**Prebuilt binary** (no Rust toolchain needed):
```bash
Verifies the published SHA-256 checksum and installs to `/usr/local/bin` or
`~/.local/bin`. Preview first with `--dry-run`.
**From crates.io** (requires Rust 1.78+):
```bash
cargo install rpi-cli
rpi --version
```
**Package managers:**
```bash
brew tap bigfish1913/tap && brew install rpi # macOS (Apple silicon), Linux
scoop bucket add bigfish1913 https://github.com/bigfish1913/scoop-bucket
scoop install rpi # Windows
```
The Homebrew formula currently supports Apple silicon on macOS. Intel Macs can
use the prebuilt installer for releases with an `x86_64-apple-darwin` asset, or
`cargo install rpi-cli`. A winget manifest is [open for
review](https://github.com/microsoft/winget-pkgs/pull/444745).
**From source:**
```bash
git clone https://github.com/bigfish1913/pi-rust.git
cd pi-rust && cargo run -p minimal # offline agent, no API key required
```
Real output of the two offline examples — no credentials, no network, identical
bytes every run. Regenerate with `task demo-transcript`:
```text
$ cargo run -q -p minimal
minimal example: 2 messages after run
- user
- assistant
assistant reply: Hello from the faux provider!
AgentEnd observed.
$ cargo run -q -p tools-example
tools example: 4 messages after run
wrote out.txt (28 bytes): "hello from the tools example"
AgentEnd observed; tool ran against OsExecutionEnv.
```
## Quick start
### The CLI
```bash
export ANTHROPIC_API_KEY=... # or OPENAI_API_KEY, or ~/.rpi/agent/models.json
rpi # interactive TUI
rpi -p "summarize the README" # one-shot
rpi --mode json -p "list the crates" # machine-readable event stream
```
Sessions persist as JSONL and survive a crash mid-run; `rpi` resumes from the
last committed frame rather than replaying the turn. Custom Anthropic or
OpenAI-compatible gateways are declared in `~/.rpi/agent/models.json` and
selected with `--model <provider>/<model>`.
### The SDK
Build an agent against a deterministic in-process provider — no API key, no
network, no flakiness:
```rust
use rpi_agent::AgentBuilder;
use rpi_ai::providers::faux::{FauxProvider, FauxScript};
use rpi_ai::Provider;
#[tokio::main]
async fn main() {
// `FauxProvider::new` already returns an `Arc<Self>`.
let provider = FauxProvider::new(FauxScript::new().with_text("Hello from the faux provider!"));
let model = provider.default_model().clone();
let agent = AgentBuilder::new()
.model(model)
.system_prompt("You are a helpful assistant.")
.stream_fn(make_stream_fn(provider))
.build()
.expect("agent builds");
let mut events = agent.subscribe();
agent.prompt("hi").await.expect("prompt completes");
while let Ok(ev) = events.try_recv() {
let _ = ev; // AgentEvent::{MessageUpdate, ToolEnd, AgentEnd, …}
}
println!("{} messages after the run", agent.state().messages.len());
}
```
`make_stream_fn` bridges the synchronous `StreamFn` contract to the async
provider — the full version is in [`examples/minimal/src/main.rs`](examples/minimal/src/main.rs)
(`cargo run -p minimal`).
## Crates
Nine crates, one version, published together. Dependency direction is one-way
and enforced in review:
```
rpi-telemetry → rpi-ai → rpi-agent → rpi-tools → rpi-harness
```
Four crates sit outside that chain:
- `rpi-tui` depends on no other `rpi-*` crate.
- `rpi-plugin-sdk` is a leaf too (it has no `rpi-*` deps), but it is not only
the host's plugin contract: `rpi-tools` also reads its env-var names, so the
host and its plugins cannot disagree about the strings they exchange across
the ABI. That edge is names-only — nothing is linked or called.
- `rpi-extensions` is `rpi-plugin-sdk` plus `rpi-ai`/`rpi-agent`, since it hosts
plugins that run tools.
- `rpi-cli` depends on all eight of the others, which is how the `rpi` binary
gets the TUI, the harness and the plugin loader at once.
| [`rpi-telemetry`](https://crates.io/crates/rpi-telemetry) | Span/event contracts with a no-op default — instrumentation is opt-in, and pulls in no tracing or OpenTelemetry backend |
| [`rpi-ai`](https://crates.io/crates/rpi-ai) | Provider-agnostic message, streaming and tool-schema types; Anthropic + OpenAI-compatible + `faux` providers |
| [`rpi-agent`](https://crates.io/crates/rpi-agent) | The agent loop: `AgentTool`, events, hooks, queues, cancellation |
| [`rpi-tools`](https://crates.io/crates/rpi-tools) | `read`/`write`/`edit`/`bash` (+ `grep`, `find`, `ls`, `powershell`) and the `ExecutionEnv` seam |
| [`rpi-harness`](https://crates.io/crates/rpi-harness) | Session tree, JSONL persistence, compaction, crash recovery, the run loop |
| [`rpi-tui`](https://crates.io/crates/rpi-tui) | Terminal UI primitives: components, layout, editor, transcript rendering |
| [`rpi-cli`](https://crates.io/crates/rpi-cli) | The `rpi` binary: TUI, one-shot and JSON modes, config, plugin loading |
| [`rpi-plugin-sdk`](https://crates.io/crates/rpi-plugin-sdk) | The stable `#[repr(C)]` ABI contract for plugins. No `rpi-*` deps; only `serde_json`, behind a default `json` feature that can be turned off |
| [`rpi-extensions`](https://crates.io/crates/rpi-extensions) | Host-side plugin loader and the async-across-ABI tool bridge |
Every crate has its own README and docs.rs page. The `crates/rpi-*`
directories and the published crate names use the same `rpi-` prefix.
## Why rpi
Most coding agents are CLIs. `rpi` is a **runtime with a CLI attached**, which
changes what you can build with it:
- **Embeddable.** The agent loop is a library. `rpi-agent` + `rpi-ai` is enough
to run an agent inside your own process, with your own event handling and
output — no shelling out to a tool and scraping stdout.
- **Testable offline.** A deterministic `faux` provider and an in-memory
execution environment are first-class, not mocks bolted on. `rpi-ai` puts its
real HTTP providers behind a `providers` feature flag, so your test suite
cannot silently depend on the network for the paths you exercise.
- **Durable.** Sessions are a tree with JSONL persistence and per-frame
progress. A crash mid-tool-call resumes instead of losing the turn or
double-executing the tool.
- **Extensible across a stable boundary.** Plugins are Rust `cdylib`s behind a
hand-written, panic-contained C ABI with version negotiation — the ABI
survives compiler and crate version skew, so extensions do not break on every
release.
- **One implementation, two surfaces.** The global CLI and an embedded agent load
the same tools. You do not maintain a plugin and a library variant separately.
### How it compares
Structural differences against other terminal coding agents. Facts about other
tools are as of 2026-09 and change often — check their documentation; only the
`rpi` column is maintained here.
| Language | Rust | TypeScript | Rust | TypeScript/Go | Python |
| Source available | ✅ MIT | ❌ | ✅ | ✅ | ✅ |
| Usable as an embedded library | ✅ | ❌ | ❌ | ⚠️ | ⚠️ |
| First-class plugin ABI | ✅ | hooks/MCP | ❌ | plugin API | ❌ |
| Headless server + remote client | ✅ | ⚠️ | ✅ | ✅ | ⚠️ |
| Provider-agnostic gateways | ✅ | ❌ | ❌ | ✅ | ✅ |
If you want the most polished single-vendor experience, use the vendor's tool.
`rpi` is for people who want to own the loop.
## Performance
Measured on Windows 11 (x86_64), rustc 1.97.1, `--release`. Both scripts
rebuild and re-measure on your own machine.
`sh scripts/bench.sh` — standalone numbers:
| Release binary size | **21.8 MiB** |
| `rpi --version` wall time | **~17 ms** median |
| RSS once the agent is ready | **12.0 MiB** |
`node scripts/bench-vs-pi.mjs --pi <path-to-pi>` — against native Pi on the same
machine, both offline, each with a fresh isolated config directory:
| `--version` | **17.5 ms** | 169.5 ms | **9.7× faster** |
| Cold start | **17.7 ms** | 189.5 ms | **10.7× faster** |
| RSS at ready | **12.0 MiB** | 91.5 MiB | **7.6× smaller** |
| Install footprint | **21.8 MiB** (one binary) | ~385 MiB (+ ~91 MiB Node) | **~18–22× smaller** |
**Cold start** is spawn → the agent answering its first command: process creation
plus full initialisation, excluding teardown and any LLM work. rpi's `--version`
(17.5 ms) and cold start (17.7 ms) are effectively equal, so startup is process
creation, not initialisation; Pi is dominated by Node boot.
Isolation caveat: rpi reads `RPI_CODING_AGENT_DIR` / `RPI_OFFLINE`, native Pi reads
`PI_CODING_AGENT_DIR` / `PI_OFFLINE`. Set the matching pair for each, or rpi
silently loads the machine's global plugins.
Method, raw per-run numbers, and what is *not* measured (LLM latency, tool-loop
throughput, long sessions, TUI frame cost) are in
[`docs/performance/benchmark-vs-pi.md`](docs/performance/benchmark-vs-pi.md).
## Plugins
Plugins are Rust `cdylib` libraries behind a stable `#[repr(C)]` ABI. A plugin
can register tools, providers, slash commands, event handlers, markdown
renderers and discovered resources.
```bash
rpi install rpi-todo # prebuilt extension; no Rust toolchain needed
rpi install my-ext --path ../my-ext # local, for development
rpi dev # build + watch + live reload
```
The host loads project `.rpi/extensions`, then global
`~/.rpi/agent/extensions`, then any `--extensions-dir`.
Ready-to-install extensions live in the companion
[`pi-rust/rpi-package`](https://github.com/pi-rust/rpi-package) repository, with
an [online catalog](https://rpi.laofu.online/packages.html).
### Optional web and subagent tools
```bash
rpi install rpi-websearch # websearch: titles, URLs and snippets
rpi install rpi-webfetch # webfetch: readable text from public pages
rpi install rpi-subagents # delegate_task: host-managed child agents
```
Restart rpi after installation. These are independent extensions, not default
CLI tools. Web search/fetch do not provide browser clicks, login flows or page
JavaScript execution.
Subagents inherit a snapshot of the parent's current model/provider binding,
thinking level, prompt, resources, request options, active tools, cwd and
approval hooks. Credentials stay inside the host. Children use independent
in-memory sessions without copying or modifying the parent history; their tool
set can only be narrowed, and recursive delegation is rejected. Parent approvals
remain in effect, and parent completion or cancellation stops the child. This is
not an OS sandbox. Use compatible host and extension versions; unsupported hosts
fail explicitly rather than starting a subprocess with different defaults.
The SDK entry point is `AgentHarness::create_child`; extensions use
`GetExecutionContext` and `ChildAgent` runtime actions. See the
[subagent protocol](https://github.com/bigfish1913/pi-rust/blob/main/docs/extensions/subagents.md)
for lifecycle, limits and compatibility details.
### Authoring an extension
```rust
use rpi_plugin_sdk::{export_plugin, StbStringRef};
export_plugin!(|api| {
if let Some(declare) = api.declare {
declare(StbStringRef::from_str(r#"{"priority":60,"platforms":["linux"]}"#));
}
// register tools / handlers through `api`
0
});
```
Start from [`examples/plugin-stub`](examples/plugin-stub) — a complete plugin
with the full `execute`→`poll`→`cancel`→`destroy` lifecycle — and read
[`docs/extensions/authoring.md`](docs/extensions/authoring.md) for the safety
rules, which are load-bearing rather than stylistic.
## Remote mode
```bash
rpi --server # headless agent over TCP, prints an auth token
rpi --connect host:port --token T # TUI client with zero local agent resources
```
The client holds no provider, tools, extensions or session files — all agent
work happens on the server, so a thin terminal anywhere can drive a beefy
machine. See [`docs/remote/user-guide.md`](docs/remote/user-guide.md).
## Project status
| Current release | **[0.6.0](https://github.com/bigfish1913/pi-rust/releases)** (nine crates, published together) |
| Stability | `rpi-ai`, `rpi-agent`, `rpi-tools`, `rpi-harness`, `rpi-plugin-sdk` are the intended stable surface |
| MSRV | 1.78 |
| Platforms | Linux, macOS, Windows (CI runs the suite on Linux) |
| Binary release targets | Linux (x86_64/aarch64), macOS (Intel/Apple silicon), Windows (x86_64) |
`rpi` is a self-contained Rust coding-agent stack. No Node component is
required and none is loaded.
## Documentation
- [User guide](docs/guides/user-guide.md) — commands, config, sessions, skills
- [Architecture](docs/architecture/overview.md) — how the crates fit together and why
- [Building an agent project](docs/agent/project-structure.md) — recommended structure
- [Extension authoring](docs/extensions/authoring.md) — plugin templates and ABI rules
- [Subagents](https://github.com/bigfish1913/pi-rust/blob/main/docs/extensions/subagents.md) — configuration inheritance, permissions and lifecycle
- [Remote mode](docs/remote/user-guide.md) — protocol, tokens, limitations
- [Roadmap](ROADMAP.md) · [Changelog](CHANGELOG.md)
- [docs.rs](https://docs.rs/rpi-cli) for per-crate API docs
## Contributing
Issues and PRs are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md) for the
build/test commands and the repository layout, and the
[roadmap](ROADMAP.md) for what is already planned. Security problems should go
through [SECURITY.md](SECURITY.md), not a public issue.
The whole test suite runs offline: `cargo test --workspace --locked`.
## Support / 赞赏支持
If rpi helps you, consider buying the author a coffee. Tips and donations support continued development and maintenance. Thank you!
如果 rpi 帮到了你,欢迎请作者喝杯咖啡,赞赏或捐助支持持续开发与维护。感谢每一份支持!
|  |  |  |
扫码或点击图片查看原图;手机上可保存图片后,在对应 App 中识别。 / Scan the code or click to view the original. On mobile, save the image and scan it from the matching app’s photo library.
## Community
Questions, ideas and early builds are welcome in either group:
<table>
<tr>
<td align="center" width="50%">
<img src="docs/images/weixin.png" width="230" alt="WeChat group QR code"><br>
<sub><b>WeChat</b> — <a href="https://weixin.qq.com/g/AQYAAD8z3FmKPk143hi_HUVOtGvNqlHWMtVZu1VGGB_46JKoNpyhJvS7kDwQwUTr">微信交流群</a></sub>
</td>
<td align="center" width="50%">
<img src="docs/images/tg.png" width="230" alt="Telegram group QR code"><br>
<sub><b>Telegram</b> — <a href="https://t.me/+7YfN4TZPP7Y0M2Q1">t.me/+7YfN4TZPP7Y0M2Q1</a></sub>
</td>
</tr>
</table>
<sub>Group invite codes expire — WeChat's rotates every few days. If a QR code stops working, open an issue and it will be refreshed.</sub>
## Acknowledgements
Thank you to Mario Zechner and the [Pi contributors](https://github.com/earendil-works/pi)
for the original TypeScript SDK and the agent, tool and session designs that
formed rpi's starting point. rpi reimplements that foundation in Rust and adds
its own runtime and extension infrastructure; it does not load the TypeScript
SDK or its npm extensions. Upstream copyright and MIT license notices are
retained in the repository's LICENSE and NOTICE files.
## License
MIT. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
The `rpi-*` crates are a Rust-native coding-agent stack.
## Star history
[](https://www.star-history.com/#bigfish1913/pi-rust&pi-rust/rpi-package&Date)