ZW

zseven-w/agent-rs

Developer tools
21 stars 3 forks Quality 61 Trend 18MIT

Pure-Rust async runtime for LLM agents. Multi-provider (Anthropic/OpenAI/Ollama), tool-capable end-to-end, structured permissions, real MCP support, USD cost tracking, Files API, optional FS+search...

Overview

Multi-provider · tool-capable end-to-end · structured permissions · real MCP · zero unsafe. That's a complete agent — provider streaming, tool dispatch, hooks, permissions, auto-compaction, USD cost tracking — all wired up. Drop in Files API attachments, MCP servers, or the bundled coding tool pack with one extra line each. agent-rs is part of the ZSeven-W AI-native product family: - zode - an AI-native coding CLI for terminal workflows, built around a Rust microkernel, plugins, multi-provider models, and a full-screen TUI. - jian - a Rust-native cross-platform UI framework where an .op file can be an app. - noema - local-first, non-vector memory for coding agents, including review queues, lexical recall, MCP, S3 offload, and enterprise policy controls. - OpenPencil - an open-source AI-native vector design tool for design-as-code workflows and concurrent Agent Teams. - No tokio::main hijack, no global state, no panic! on bad input. #![forbid(unsafe_code)] in every crate.

README


TL;DR

use agent::prelude::*;
use std::sync::Arc;

let provider = Arc::new(AnthropicProvider::new(std::env::var("ANTHROPIC_API_KEY")?));
let engine = QueryEngine::new(provider, "claude-opus-4-7").with_system("Be concise.");

let mut stream = engine.run("Summarize Rust's borrow checker in two lines.", AbortController::new()).await?;
while let Some(event) = futures::StreamExt::next(&mut stream).await {
    if let Event::TextDelta { delta } = event? { print!("{delta}") }
}

That’s a complete agent — provider streaming, tool dispatch, hooks, permissions, auto-compaction, USD cost tracking — all wired up. Drop in Files API attachments, MCP servers, or the bundled coding tool pack with one extra line each.


ZSeven-W Products

agent-rs is part of the ZSeven-W AI-native product family:

  • zode - an AI-native coding CLI for terminal workflows, built around a Rust microkernel, plugins, multi-provider models, and a full-screen TUI.
  • jian - a Rust-native cross-platform UI framework where an .op file can be an app.
  • noema - local-first, non-vector memory for coding agents, including review queues, lexical recall, MCP, S3 offload, and enterprise policy controls.
  • OpenPencil - an open-source AI-native vector design tool for design-as-code workflows and concurrent Agent Teams.

Why agent-rs?

  • 🦀 Rust-native, library-only. No tokio::main hijack, no global state, no panic! on bad input. #![forbid(unsafe_code)] in every crate. Drop it into a CLI, an IDE plugin, a desktop app, or a server — the runtime doesn’t care.
  • 🔌 Three providers, one event vocabulary. Anthropic Messages (hand-rolled SSE — full prompt-cache + extended-thinking betas, no SDK dep), async-openai 0.36 (DeepSeek / Moonshot / Groq / OpenRouter / LM Studio), and local Ollama. Stream Event::TextDelta, ToolUse, Usage, Result — same shape from every backend.
  • 🛠 Tool-capable end-to-end. Define a tool, register it, the runtime wires the JSON Schema into the request body, dispatches ToolUse events to your code, feeds results back. Multi-turn loop with a phase machine. Receipt-order concurrent execution. Permissions and cost tracking are wired through, not bolted on.
  • 🛡 Structured permissions that fail safe. A 7-step decision chain (deny / ask / callback / bypass / allow / default-ask / dont_ask), composable PermissionMatcher rules over tool input shapes (JSON-pointer fields, glob/prefix/regex patterns, AnyOf / AllOf / Not), and a 4-level SafetyClass lattice where Unknown ≡ Destructive for gating — so unclassified tools never slip through.
  • 🔗 MCP that actually plugs in. Full Model Context Protocol client lifecycle: stdio child processes, streamable HTTP, OAuth 2.0 + PKCE, server-initiated elicitation, channel permissions, stale-handle reconnect repair. Tool calls don’t serialize on a mutex. close() doesn’t deadlock during slow RPCs.
  • 💸 Cost accounting in nanodollar precision. Event::Usage flows into a CostTracker with a model-price catalog (Anthropic + GPT defaults, BYO entries trivially). u128 integer accumulator — no f64 drift across long sessions.
  • 📎 Files API for big attachments. FilesClient trait + AnthropicFilesClient. Smart helpers auto-route between inline base64 and uploaded file_id references based on size. Beta header gets added automatically when any block (including those nested in tool results) carries a file_id.
  • ♻️ Reactive auto-compaction. Token estimator + LLM-driven `` / `

Foundation

Module Purpose
provider/ Multi-provider LLM client. Tool definitions wired into request bodies; capability flags + streaming Event vocabulary.
query/ QueryLoop multi-turn phase machine. Reactive auto-compaction wired in.
tool/ Tool trait, ToolRegistry, SafetyClass lattice. Receipt-order concurrent execution via ToolExecutor.
permission/ 7-step chain + structured PermissionMatcher (Always / Field / ExactJson / AnyOf / AllOf / Not) + StringPattern. External-queue async approval.
hook/ 27 typed HookEvent variants.
message/ DAG-aware MessageStore. ContentBlock::Document for PDFs; ImageSource::File for Files-API references.
stream/ Event taxonomy: TextDelta / Thinking / ToolUse / ToolResult / Result / Usage / Error / Notice.
session/ JSONL persistence (schema v1) with atomic-rename + file lock.
swarm/ Sub-agents / teams. File-locked mailbox, in-process / tmux / iTerm2 backends.
compact/ Reactive auto-compaction. LLM-driven summarization, partial directions, microcompact, session memory.
context/ Sliding-window trim.

Service layer

Module Purpose
api/ Retry with decorrelated jitter, error classification, prompt-cache-break detection, secret redaction.
cost/ Model-price-aware USD accounting. u128 nanodollars — no f64 drift.
attachments/ FilesClient + AnthropicFilesClient, smart size-aware routing.
tokenizer/ Pluggable trait. Real tiktoken plugs in via the trait.

Discovery + extensibility

Module Purpose
mcp/ (feature mcp) Full MCP client + production RmcpConnector.
memdir/ MEMORY.md directory loader with frontmatter + relevance scoring.
skills/ · plugins/ · state/ · bootstrap/ · context_analysis/ · tasks/ · memory_extract/ · remote/ See crates/agent/src/.

Design principles

Library-only. No global state, no tokio::main, no panic! on bad input — every error path is a typed AgentError.

Provider-agnostic at the runtime layer. Concrete tools live outside the agent crate. The runtime defines the trait; companions ship implementations.

Streaming first. Every provider is a streaming source. Multi-turn / tool dispatch / compaction are coordinated through one Event vocabulary, no polling.

Cancellation everywhere. Every async surface honors an AbortController — including the tokio::task::spawn_blocking workers used by Grep / Glob.

No unsafe. #![forbid(unsafe_code)] in both crates.

Defensive against the model. Permissions fail safe (Unknown ≡ Destructive for gating). Tool schemas validated before reaching the wire. Path operations canonicalize before any I/O. Idempotent writes detect no-ops.

Cost-aware. Tool schemas, prompt cache, and token usage feed an integer-precision USD accumulator. Long-running sessions don’t drift.


Testing

cargo test --workspace --all-features
# 844 unit · 13 integration · 5 doc · 4 ignored (real-API gates)

cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo fmt --all -- --check
cargo deny --all-features check

The 4 #[ignore]-gated tests hit real APIs (Anthropic / OpenAI / Ollama / Anthropic Files) when their environment variables are set. CI runs the full suite with mocks; real-API runs are manual.


Status

This is a pre-release project — every change lives under Unreleased in CHANGELOG.md until 0.1.0 ships. The runtime API surface has stabilized and 863 tests guard it; the open work is wiring more tools into the optional companion crate and tagging a release.

See openpencil-docs/agent-rs/notes/2026-05-02-claude-code-non-tui-gaps.md for what’s intentionally host-side vs. what’s pending.


Contributing

PRs welcome. Two ground rules:

  1. No product-specific imports in the agent crate. Generic concepts only — anything tied to a specific app belongs in a downstream crate.
  2. Adversarial review every change. Open an issue first for anything bigger than a small fix so we can align on direction.

View the full README on GitHub

Install

This server does not publish a one-line install command.

Open the repository installation guide New to MCP? Start with the mcpskill.org guide →