rpi-agent 0.1.0

Agent runtime + loop, Rust port of pi-agent-core core layer
Documentation

rpi — Rust port of the Pi agent SDK

A Rust port of earendil-works/pi's SDK layer — a library-first, multi-crate workspace for building personal LLM coding agents in Rust, plus an rpi CLI built on top.

Naming. The published crates use the rpi- prefix (the upstream pi-* names are owned on crates.io by a parallel port). The on-disk directories stay crates/pi-* for history; the package.name in each Cargo.toml is rpi-*, so extern crate / use paths are rpi_ai, rpi_agent, etc.

Crates (published as rpi-*)

Crate (crates.io) On-disk dir What it is
rpi-telemetry pi-telemetry/ Telemetry span/event contracts (noop default).
rpi-ai pi-ai/ Unified multi-provider LLM types + streaming (Anthropic + faux).
rpi-agent pi-agent/ Agent runtime + loop, AgentTool trait, events, hooks, queues.
rpi-tools pi-tools/ Built-in tools (read/write/edit/bash/grep/find/ls) + ExecutionEnv.
rpi-harness pi-harness/ AgentHarness: session tree, JSONL persistence, compaction, run loop.
rpi-cli pi-cli/ Terminal coding-agent CLI (rpi binary) on top of the library crates.

Dependency direction: rpi-telemetry → rpi-ai → rpi-agent → rpi-tools → rpi-harness → rpi-cli.

Relationship to the TypeScript source

The TypeScript reference is checked out under .reference/pi/ (read-only). Every Rust module names the TS file it mirrors in its module-level doc comment. The crate family is a Rust-native reimplementation, not a thin wrapper — it ports the SDK surface (pi-ai, pi-agent-core, the harness tools, the session layer) and the CLI, keeping the layering and behavior faithful while using idiomatic Rust (async/await, Arc, serde, tokio).

How you build an agent

use rpi_agent::{Agent, AgentTool, AgentEvent};
use rpi_ai::{providers::faux::faux_provider, Model};

let model = faux_provider().model("echo");
let mut agent = Agent::builder(model)
    .system_prompt("You are a helpful assistant.")
    .tool(MyTool)
    .build();

let mut events = agent.subscribe();
tokio::spawn(async move {
    while let Some(ev) = events.recv().await {
        match ev { /* AgentEvent::MessageUpdate { .. }, etc. */ }
    }
});

agent.prompt("Hello!").await.unwrap();

See docs/architecture.md for the full design.

Status (v1)

  • Providers: Anthropic (API-key auth) + a faux provider for tests. OAuth / Copilot auth is deferred — bring an ANTHROPIC_API_KEY.
  • Tools: read, write, edit, bash (mutating, run through a MutationQueue) + grep, find, ls (read-only, in-process via the FileSystem trait — no rg/fd shell-out).
  • Sessions: JSONL v4 durable backend + in-memory ephemeral; compaction + a split-turn two-LLM-call invariant.

Releasing

Publish the crate family with release.ps1 (Windows) or release.sh (Unix/CI), dep-ordered, dry-run by default:

./release.ps1            # safe dry run
./release.ps1 -DryRun    # same, explicit
./release.ps1 -Publish   # real publish to crates.io (run `cargo login` first)

License

MIT. See LICENSE.