yoagent
Library Listed
The agent loop for Rust: stream from 7 LLM protocols, run tools, loop until done. Native or wasm32 (Cloudflare Workers).
- Downloads
- 2,027
- Dependents
- 5
- Stars
- 369
- Forks
- 53
- Contributors
- 6
- Commits
- 464
- Latest release
- 0.27.4 ·
About

Getting started · Design philosophy · Docs · API · Changelog · 中文
The agent loop for Rust. Stream from any LLM protocol, run tools and extensions, loop until done.
A loop library, not an agent: it powers yoyo, a coding agent evolving its own source since March 2026. Your agent ships as one native binary, or builds for wasm32 to run in a Cloudflare Worker.
Try it in one command — no API key
git clone https://github.com/yologdev/yoagent && cd yoagent
ollama serve &
ollama pull llama3.1:8b # or pass --model <any pulled model>
cargo run --example cli -- --provider ollama
That's a working coding agent in your terminal — file read/write/edit, shell, ripgrep search, streaming output, skills. No signup, no key, nothing to configure.
yoagent cli — mini coding agent
Type /quit to exit, /clear to reset
model: llama3.1:8b
cwd: /home/user/my-project
> find all TODO comments in src/
▶ search 'TODO' ✓
Found 3 TODOs:
src/main.rs:42: // TODO: handle edge case
src/lib.rs:15: // TODO: add tests
src/utils.rs:8: // TODO: optimize this
tokens: 1250 in / 89 out
Point it at a hosted model instead by swapping the flag:
Read the full README
ANTHROPIC_API_KEY=sk-... cargo run --example cli
GROQ_API_KEY=... cargo run --example cli -- --provider groq --model openai/gpt-oss-120b
cargo run --example cli -- --api-url http://localhost:1234/v1 --model my-model # LM Studio, llama.cpp, vLLM
Install
[dependencies]
yoagent = "0.27"
tokio = { version = "1", features = ["full"] }
Building for wasm32? Use default-features = false (see
WebAssembly & Cloudflare Workers).
On a native target keep the default native feature: without it reqwest has no TLS, and every
HTTPS provider call fails at runtime.
Quick start
An agent that actually uses a tool — the thing the crate exists for:
use yoagent::provider::ModelConfig;
use yoagent::{tools, Agent, AgentEvent, StreamDelta};
#[tokio::main]
async fn main() {
// The provider is selected from the config's protocol and the key is read
// from ANTHROPIC_API_KEY. Call `.with_api_key(k)` to pass one explicitly.
let mut agent = Agent::from_config(ModelConfig::claude_sonnet_5())
.with_system_prompt("You are a coding assistant.")
.with_tools(tools::default_tools());
let mut events = agent.prompt("Find every TODO in src/ and summarise them").await;
while let Some(event) = events.recv().await {
match event {
AgentEvent::MessageUpdate { delta: StreamDelta::Text { delta }, .. } => print!("{delta}"),
AgentEvent::ToolExecutionStart { tool_name, .. } => println!("\n▶ {tool_name}"),
AgentEvent::AgentEnd { .. } => break,
_ => {}
}
}
agent.finish().await;
}
Swap the model by swapping the config — the provider follows, and the key is read from that provider's conventional env var:
Agent::from_config(ModelConfig::groq("openai/gpt-oss-120b", "GPT-OSS 120B")); // GROQ_API_KEY
Agent::from_config(ModelConfig::gemini_3_8_flash()); // GEMINI_API_KEY
Agent::from_config(ModelConfig::ollama("http://localhost:11434/v1", "llama3.1:8b")); // no key
Why yoagent
Every agent runs the same loop, and almost every hand-written one gets the same things wrong: streams that end badly, tools that panic or hang, context that runs out, runs that never stop, spend nobody can account for. yoagent writes that loop once, with each guarantee pinned by a test, and keeps one rule for what goes in: does every agent need it, the same way? Anything else is an extension, a feature or a companion crate (design philosophy).
So it ships no vector stores, embedding pipelines, or task-graph layer — if your problem is retrieval or orchestration, one of these is the better fit:
| If you need | Look at |
|---|---|
| RAG pipelines, vector stores, embeddings, transcription and image generation | rig — "Build modular and scalable LLM Applications in Rust" |
| Typed task graphs and streaming RAG indexing alongside agents | swiftide — "Composable LLM agents and harness, typed task graphs, and streaming RAG pipelines in Rust" |
| A tool-calling loop you host, gate, steer, branch, and record | yoagent |
What that focus bought:
- The loop is a free function.
agent_loop()is stateless and takes everything it needs as arguments.Agentis an optional wrapper that adds history and queues. You can drive the loop yourself without adopting our state model. - 7 native wire protocols, not one OpenAI-compat shim with adapters bolted on. Anthropic Messages, OpenAI Completions, OpenAI Responses, Azure, Gemini, Vertex, and Bedrock each have a real implementation, so provider-specific features (thinking budgets, prompt-cache breakpoints, reasoning deltas) survive instead of being flattened away.
- One plug-in contract for the whole run. An
Extensioncan add tools, check input, allow, modify or deny each tool call, redact results, and check the final answer, with state that starts fresh each run. Install it as host policy and it governs every sub-agent too. Hooks that guard a call fail closed: a policy that cannot run denies, an input check rejects, a redaction that fails withholds. - Steer a run that's already going. Inject guidance mid-flight; it's picked up between tool batches without restarting the turn.
- History is a tree, not a list.
Sessionforks, checkpoints, and seeks. Edit an earlier turn and re-run it without destroying the original branch. - Runs are recordable. With
features = ["gasp"], a run becomes an append-only semantic event log in a git repo — restore is clone + replay. Conformance-checked in CI. - The whole loop is testable offline.
MockProviderscripts multi-turn tool-calling conversations and honours cancellation, so abort and steering paths are testable with no network or key.
Extend it
Everything that changes what the loop does goes through one contract, Extension: its run's
RunHooks see on_input, before_model, before_tool, after_tool, on_stop, every event,
and finish. A tool policy is a few lines:
use yoagent::extension::{ClonedHooks, RunHooks};
use yoagent::{ToolCallRequest, ToolDecision};
#[derive(Clone)]
struct NoForcePush;
#[async_trait::async_trait] // the `async-trait` crate
impl RunHooks for NoForcePush {
async fn before_tool(&self, call: &ToolCallRequest<'_>) -> ToolDecision {
let command = call.args["command"].as_str().unwrap_or_default();
if command.contains("push --force") {
ToolDecision::Deny("force-push is not allowed here".into())
} else {
ToolDecision::Allow
}
}
}
let agent = agent.with_extension(ClonedHooks::new("no-force-push", NoForcePush));
yoagent's own budget, tool gate and input guard are built the same way. Six runnable
extension_* examples cover policies, redaction, verifiers, budgets, sub-agent policy and
audit logs (guide).
Plugins and other ecosystems. yoagent-rutis turns
rutis plugins — Rust, TypeScript (Node or Bun), Python or Go, loaded,
reloaded and unloaded at runtime — into one Extension. Through small adapters it also runs many
pi extensions and DeepSeek harness (DSH) tool plugins unchanged, with no
change to yoagent's core: tools, tool policies, input checks, prompt additions and images cross
over; commands and UI don't. An extension that hooks something the adapter can't enforce is
refused, not half-run. How the 20 most-downloaded packages of each ecosystem fare (by monthly
downloads, among npm's first 1000 search results per keyword), measured:
plugin compatibility.
Agents built this way — a coding agent with pi and DSH plugins in your browser, a handoff agent
that asks without waiting and reports back — live in yobuild.
Runs where agents run
The same loop builds natively and for wasm32-unknown-unknown. In yoyo's Cloudflare Worker we
measured about 4 ms to start and a median of ~45 ms of CPU per agent run — an agent
spends most of a run waiting on the model, which Workers do not bill as CPU. A minimal Worker
(one provider via Agent::from_provider, one tool, no decision model) is about 330 KiB gzipped. HTTP MCP works over the host's fetch;
yoagent-workers turns the Workers AI binding into a decision
model. See WebAssembly & Cloudflare Workers.
Built with yoagent
yoyo-evolve — a coding
agent that evolves its own source in public. It began as 200 lines of Rust; every commit since has
been agent-written and gated on tests. It runs on this loop with the openapi feature enabled.
Also built on yoagent:
| Project | What it is |
|---|---|
rab | A lightweight, extensible Rust coding agent |
greatsage | "Rimuru's Unique Skill, you know the one" |
yoclaw | OpenClaw reborn in Rust — a single-binary agent that remembers you |
Built something on yoagent? Open a PR and add it here — we'd like to see it.
What's in the box
| The loop | Full event stream; parallel, sequential or batched tools; steering and follow-ups; execution limits; retry with backoff and jitter; unanswered tool calls closed | Agent loop · Events · Retry |
| Extensions | One plug-in contract for the run; on_stop sees cut-off answers too; Budget; the older hooks (ToolMiddleware, input filters, TurnHook, callbacks) still work | Extensions · Callbacks |
| Providers | 7 native protocols reaching 20+ providers, or your own StreamProvider; thinking controls; prompt-cache hints; one context-overflow classifier; images sent the way each protocol takes them, or a text note with image_input off | Providers · Prompt caching |
| Tools | bash, file read/write/edit, list_files, search; custom tools via one trait; MCP over stdio or HTTP; OpenAPI specs; ToolSources (refreshed mid-run, MCP list_changed included); per-file locking, images checked before sending, no overwrite after a partial read (ReadLog, on in default_tools()) | Tools · MCP · OpenAPI |
| Sub-agents | Child loops with their own model and tools; large artifacts passed by reference; spend rolled up | Sub-agents |
| Context | Usage-calibrated tracking, tiered compaction, optional LlmCompaction, loop detection | Context management |
| Sessions, skills, structured output | Branching session trees with JSONL; AgentSkills SKILL.md; typed prompt_structured::<T>() | Sessions · Skills · Structured outputs |
Decision models (decision) | Typed yes/no, one-of-N and score judgments in a few hundred ms (Jev, Clef, OpenAI Decisions, any logprobs server); a tool gate and an input guard | Decision models |
| Cost and telemetry | Opt-in pricing (nothing priced by default); model limits from the same table, applied even with pricing off; SessionStats per run incl. sub-agents; tracing spans with tokens and cost | Pricing · Telemetry |
Recording (gasp) | serde on every core type; runs recorded into a GASP repo, plugin logs too (opt-in) | Persistence · GASP |
| WebAssembly | --no-default-features for wasm32-unknown-unknown, e.g. Cloudflare Workers | WebAssembly & Workers |
Examples
Seventeen of the 22 runnable examples in examples/ are below; ten need no API key at all (eleven counting cli with a local model). The rest are live-provider harnesses and offline evaluation sweeps.
| Example | What it shows | Key needed |
|---|---|---|
cli | A ~400-line coding agent — all tools, skills, streaming, colored output. Like a baby Claude Code | optional¹ |
rlm | An LLM that explores a codebase on its own by spawning sub-agents | yes |
code_review | Three sub-agents reviewing a diff in parallel, results merged | yes |
shared_state | Passing a large artifact between sub-agents by reference | yes |
sub_agent | Delegation basics with a per-sub-agent model | yes |
basic | The smallest possible agent | yes |
callbacks | Lifecycle hooks and a custom tool | no |
persistence | Save and restore a session | no |
telemetry | tracing spans with token and cost fields | no |
gasp_emit | Recording a run into a GASP repo | no |
decision | Decision-model questions in one line, and attaching a model to an agent (feature decision) | yes |
extension_policy, _redact, _verifier, _budget, _tree, _audit | Extensions: a tool policy, redaction, a verifier, budgets, policy over sub-agents, an audit log (guide) | no² |
¹ --provider ollama or --api-url needs no key; hosted providers read their conventional env var.
² Scripted offline by default; -- --live uses DEEPSEEK_API_KEY or ANTHROPIC_API_KEY.
The companion crates have their own: language_plugins, pi_extensions and dsh_tools
(TypeScript, Python, pi and DSH plugins) and a Clef tool-gate Worker.
Testing
MockProvider scripts a whole multi-turn tool-calling conversation with no network, and honours
cancellation, so abort and steering paths are testable too. See
Testing Your Agent; how the crate itself is tested and what CI runs is
in CONTRIBUTING.
Documentation
- The book — concepts, guides, a page per provider, and the architecture and module map (source)
- Design philosophy — why yoagent is a loop library, the one extension contract, and what that costs
- API reference — built with all features enabled
- For coding agents: the yoagent skill — which feature for which job, tips and pitfalls, what changed per version (AgentSkills
SKILL.md; also in the published crate) — andllms.txt, a map of every docs page - CHANGELOG — every release
- CONTRIBUTING — how to build, test, and send a PR
MSRV is 1.86, enforced in CI. Raising it is a minor-version change.
Contributing
Bug reports, ideas and PRs are welcome — open an issue or pick one labelled help wanted. CONTRIBUTING covers building, the checks CI runs, and the PR checklist. Report security issues privately as described in SECURITY.
Acknowledgements
rutis, the plugin runtime behind yoagent-rutis, and the
contributors who send fixes and ideas — including the ones who suggest them on X.
License
MIT — see LICENSE.
Compatibility
- Runs on
- GPU support unknown
What shows it
- no dependency or feature matches a backend row
- Native code
- None found
- No native code found
- Python bindings
- No Python binding crate found
- License
- MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
The agent loop for Rust: stream from 7 LLM protocols, run tools, loop until done. Native or wasm32 (Cloudflare Workers). |
2,027 downloads over 30 days | 5 | 369 | 0.27.4 | GPU support unknown | No native code found | MIT |
|
adk-rust Listed
Rust Agent Development Kit - Build AI agents in Rust with modular components for models, tools, memory, and more. |
5,419 downloads over 30 days | 25 | 743 | 2.3.0 | CUDA, Metal | Binds native code: alsa-sys (feature desktop-audio), audiopus_sys (feature openai-webrtc), cxx (feature livekit), espeak-rs-sys (feature kokoro), libsqlite3-sys (feature sqlite) and 4 more | Apache-2.0 |
|
langchain-rust Listed
LangChain for Rust, the easiest way to write LLM-based programs in Rust |
4,306 downloads over 30 days | 4 | 1,362 | 8.0.0 | GPU support unknown | Binds native code: tree-sitter (feature tree-sitter), ort-sys (feature fastembed), ring (feature surrealdb), tree-sitter-language (feature tree-sitter). Build uses a native toolchain: cc (feature tree-sitter) | MIT |
|
chidori Listed
The agent framework where every run is durable, replayable, and resumable by default. Plain async TypeScript agents on an embedded pure-Rust JS engine. Python bindings |
257 downloads over 30 days | 0 | 1,372 | 3.8.1 | GPU support unknown | Binds native code: aws-lc-rs, aws-lc-sys, lcms2-sys, libffi-sys, libsqlite3-sys and 4 more | Apache-2.0 |
|
The autonomous, self-improving AI agent. Single Rust binary. Every channel. Recommended: the 40MB prebuilt binary for macOS, Linux and Windows: https://github.com/opencrabs/opencrabs/releases |
125 binary downloads per release | Not applicable | 1,027 | 0.5.15 | GPU support unknown | Binds native code: libsqlite3-sys, llama-cpp-sys-2, opusic-sys (feature local-tts), tree-sitter (feature code-graph), alsa-sys (feature local-stt) and 1 more | MIT |
|
Rust-native, library-first coding-agent runtime and terminal CLI inspired by Pi, with composable LLM providers, tools, sessions, and plugin ABI |
16 binary downloads per release | Not applicable | 231 | Not measured | Not measured | MIT | |
|
An open protocol that gives AI agents a secure, sandboxed place to run code and use tools — with lean context usage. AXP works alongside MCP |
Not measured | Not applicable | 3 | Not measured | Not measured | Not measured | Apache-2.0 |
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- It has 1 active dependents and 1 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 369 stars, 53 forks and 6 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.
What else the check found
- The last activity is on 8 Nov 2026, 1 day ago. The rules expect an update within 450 days. Dormancy rule
Exact rules: Listed, Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.27.4 base 450: E = 450 daysdormancy: last activity 2026-11-08, 1 days ago, E = 450: activefeatured: not featured: active_users 1 < 11 and new_adopters 1 < 9 and repository route stars 369 (needs 4539), forks 53 (needs 434), contributors 6 (needs 79)listed: listed: no archive, new or featured rule applies
Crates3 crates
- yoagent Primary
- yoagent-rutis
- yoagent-workers
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the crates.io description
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption1 active dependents, 1 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 1 | crates.io database dump | Yes | |
| New dependents (365 days) | 1 | crates.io database dump | Yes | |
| Peak active dependents | 2 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 1 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 1 day ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-11-08 | GitHub repository | Yes | |
| Latest release | 2026-11-07 | crates.io database dump | Yes | |
| First release | 2026-02-17 | crates.io database dump | Yes | |
| Latest version | 0.27.4 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 0 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 31 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | none | crates.io database dump | Yes |
Distribution83 releases, 2,027 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 83 | crates.io database dump | Yes | |
| Downloads over 30 days | 2027 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository369 stars, 53 forks, 6 contributors, 464 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 369 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 53 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 6 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 464 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | GPU support unknown | crates.io database dump | No | |
| What shows each backend | no dependency or feature matches a backend row | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | No native code found | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 5 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.