Phi Rust extension SDK (ext/rust)
Rust is a first-class language for Phi extensions — on par with the Go SDK
in ext/go. Same PXB wire protocol on stdin/stdout, same host
features (LLM tools, slash commands, intercepts, event subscriptions, confirm
dialogs), byte-for-byte interop, and the same install flow (phi.yaml + a
binary under ~/.phi/extensions/<name>/). The only dependencies are
serde/serde_json at the JSON edges (tool schemas, confirm payloads) plus
tokio (rt feature) to drive async tool handlers; the
PXB wire codec stays hand-rolled — no reflection, no runtime protocol deps.
Wire compatibility with the Go SDK is pinned byte-for-byte by golden tests
against ext/go/pxb/testdata/*.bin (tests/pxb_test.rs).
Layout
| Path | Role |
|---|---|
src/pxb/ |
Wire protocol: frames (codec), tagged fields (fields), message codecs (msg), types/events (types) |
src/phi/ |
Author SDK: Extension, Tool, Command, Context, Schema |
examples/ |
Runnable extensions: hello (commands, intercepts, subscribe), full (tool, confirm, submit) |
tests/ |
Golden byte-compat + end-to-end fake-host tests |
Authoring
The crate publishes to crates.io; release tags are ext/rust/vX.Y.Z. Until
the first publish, depend on it from the repo (main); after a release, use
the published version:
[]
# pre-release: tracks the latest main
= { = "https://github.com/pulseaiclub/phi", = "main" }
# release: published crate version (tagged ext/rust/vX.Y.Z)
# phi-ext = "0.1.0"
use ;
Tools are usually IO-bound, so handlers may be async — the SDK runs them on a single-threaded tokio runtime that blocks the PXB loop the same way a sync handler would (the host waits for the result anyway):
use phi;
m.register_tool;
Sync handlers keep working unchanged via [phi::Tool::new] — the two share
one storage type, so a tool can switch to async without touching its schema.
Command handlers get a phi::Context for host interaction:
notify, set_status, submit, send_user_message, confirm,
confirm_opts. Commands themselves stay synchronous: their Context reads
nested PXB frames off the same pipe, which only works on the loop thread.
Build and install (a phi.yaml manifest must live next to the binary):
Reload in the TUI: Ctrl+K → extensions → reload.
PXB codec numbers (vs Go / JSON lines) live in the root
README. Re-run the probe with
cargo run --release --example bench.
Development
The run loop is single-threaded; the borrow checker replaces the Go SDK's
mutexes (handlers get &mut state and cannot alias the registry).