yologdev/yoagent

The agent loop for Rust — stream from 7 LLM protocols, run tools, loop until done.

Rust

363

298 commits

updated Oct 19, 2026

See the code

See what people are saying

SourceMessageScoreDate

Does reusing pi extensions and DeepSeek Harness plugins make sense in a Rust agent runtime? (r/rust)

If you're building an agent in Rust, would being able to reuse pi extensions and DeepSeek Harness (DSH) plugins be useful to you? I've been exploring this with yoagent, a small agent loop in Rust. It handles model streaming, tool execution, retries, cancellation, and limits. **The loop stays small;…

0

Oct 12, 2026

Would you use pi extensions and DeepSeek Harness plugins in a Rust agent runtime (r/LLMDevs)

https://reddit.com/link/1x3xbmd/video/0imh3x4g90vh1/player If you're building an agent in Rust, would being able to reuse pi extensions and DeepSeek Harness (DSH) plugins be useful to you? I've been exploring this with [yoagent](https://github.com/yologdev/yoagent), a small agent loop in Rust. It…

5

Oct 12, 2026

README

yoagent

Getting started · Design philosophy · Docs · API · Changelog · 中文

The agent loop for Rust. Stream from any of 7 LLM protocols, run tools, loop until done.

A loop library, not an agent: it powers yoyo, a coding agent evolving its own source since March 2026, and runs from a laptop to a Cloudflare Worker.

The yoagent loop: prompt, context, LLM stream, tool calls through a gate and back, a finish check, limits, and the Extension hooks at each step

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:

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.25"
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::google("gemini-3.8-flash", "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 needLook at
RAG pipelines, vector stores, embeddings, transcription and image generationrig — "Build modular and scalable LLM Applications in Rust"
Typed task graphs and streaming RAG indexing alongside agentsswiftide — "Composable LLM agents and harness, typed task graphs, and streaming RAG pipelines in Rust"
A tool-calling loop you host, gate, steer, branch, and recordyoagent

What that focus bought:

  • The loop is a free function. agent_loop() is stateless and takes everything it needs as arguments. Agent is 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 Extension can 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. Session forks, 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. MockProvider scripts 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 or Python, 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. scripts/try-coding-agent.sh serves a coding agent with pi and DSH plugins for your browser; scripts/try-handoff.sh "<task>" hands a task to an agent that asks without waiting and reports back.

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:

ProjectWhat it is
rabA lightweight, extensible Rust coding agent
greatsage"Rimuru's Unique Skill, you know the one"
yoclawOpenClaw 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 loopFull event stream; parallel, sequential or batched tools; steering and follow-ups; execution limits; retry with backoff and jitterAgent loop · Events · Retry
ExtensionsOne plug-in contract for the run; Budget; the older hooks (ToolMiddleware, input filters, TurnHook, callbacks) still workExtensions · Callbacks
Providers7 native protocols reaching 20+ providers; thinking controls; prompt-cache hints; one context-overflow classifierProviders · Prompt caching
Toolsbash, file read/write/edit, list_files, search; custom tools via one trait; MCP over stdio or HTTP; OpenAPI specs; per-run ToolSourcesTools · MCP · OpenAPI
Sub-agentsChild loops with their own model and tools; large artifacts passed by reference; spend rolled upSub-agents
ContextUsage-calibrated tracking, tiered compaction, optional LlmCompaction, loop detectionContext management
Sessions, skills, structured outputBranching 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 guardDecision models
Cost and telemetryOpt-in pricing (nothing priced by default); SessionStats per run incl. sub-agents; tracing spans with tokens and costPricing · 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 WorkersWebAssembly & 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.

ExampleWhat it showsKey needed
cliA ~400-line coding agent — all tools, skills, streaming, colored output. Like a baby Claude Codeoptional¹
rlmAn LLM that explores a codebase on its own by spawning sub-agentsyes
code_reviewThree sub-agents reviewing a diff in parallel, results mergedyes
shared_statePassing a large artifact between sub-agents by referenceyes
sub_agentDelegation basics with a per-sub-agent modelyes
basicThe smallest possible agentyes
callbacksLifecycle hooks and a custom toolno
persistenceSave and restore a sessionno
telemetrytracing spans with token and cost fieldsno
gasp_emitRecording a run into a GASP repono
decisionDecision-model questions in one line, and attaching a model to an agent (feature decision)yes
extension_policy, _redact, _verifier, _budget, _tree, _auditExtensions: 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

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.

agent
agent-framework
ai
ai-agents
anthropic
claude
coding-agent
gemini
llm
llm-agent
mcp
openai
rust
streaming
tool-calling

yologdev/yoagent

The agent loop for Rust — stream from 7 LLM protocols, run tools, loop until done.

Rust

363

298 commits

updated Oct 19, 2026

See the code

See what people are saying

SourceMessageScoreDate

Does reusing pi extensions and DeepSeek Harness plugins make sense in a Rust agent runtime? (r/rust)

If you're building an agent in Rust, would being able to reuse pi extensions and DeepSeek Harness (DSH) plugins be useful to you? I've been exploring this with yoagent, a small agent loop in Rust. It handles model streaming, tool execution, retries, cancellation, and limits. **The loop stays small;…

0

Oct 12, 2026

Would you use pi extensions and DeepSeek Harness plugins in a Rust agent runtime (r/LLMDevs)

https://reddit.com/link/1x3xbmd/video/0imh3x4g90vh1/player If you're building an agent in Rust, would being able to reuse pi extensions and DeepSeek Harness (DSH) plugins be useful to you? I've been exploring this with [yoagent](https://github.com/yologdev/yoagent), a small agent loop in Rust. It…

5

Oct 12, 2026

README

yoagent

Getting started · Design philosophy · Docs · API · Changelog · 中文

The agent loop for Rust. Stream from any of 7 LLM protocols, run tools, loop until done.

A loop library, not an agent: it powers yoyo, a coding agent evolving its own source since March 2026, and runs from a laptop to a Cloudflare Worker.

The yoagent loop: prompt, context, LLM stream, tool calls through a gate and back, a finish check, limits, and the Extension hooks at each step

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:

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.25"
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::google("gemini-3.8-flash", "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 needLook at
RAG pipelines, vector stores, embeddings, transcription and image generationrig — "Build modular and scalable LLM Applications in Rust"
Typed task graphs and streaming RAG indexing alongside agentsswiftide — "Composable LLM agents and harness, typed task graphs, and streaming RAG pipelines in Rust"
A tool-calling loop you host, gate, steer, branch, and recordyoagent

What that focus bought:

  • The loop is a free function. agent_loop() is stateless and takes everything it needs as arguments. Agent is 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 Extension can 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. Session forks, 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. MockProvider scripts 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 or Python, 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. scripts/try-coding-agent.sh serves a coding agent with pi and DSH plugins for your browser; scripts/try-handoff.sh "<task>" hands a task to an agent that asks without waiting and reports back.

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:

ProjectWhat it is
rabA lightweight, extensible Rust coding agent
greatsage"Rimuru's Unique Skill, you know the one"
yoclawOpenClaw 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 loopFull event stream; parallel, sequential or batched tools; steering and follow-ups; execution limits; retry with backoff and jitterAgent loop · Events · Retry
ExtensionsOne plug-in contract for the run; Budget; the older hooks (ToolMiddleware, input filters, TurnHook, callbacks) still workExtensions · Callbacks
Providers7 native protocols reaching 20+ providers; thinking controls; prompt-cache hints; one context-overflow classifierProviders · Prompt caching
Toolsbash, file read/write/edit, list_files, search; custom tools via one trait; MCP over stdio or HTTP; OpenAPI specs; per-run ToolSourcesTools · MCP · OpenAPI
Sub-agentsChild loops with their own model and tools; large artifacts passed by reference; spend rolled upSub-agents
ContextUsage-calibrated tracking, tiered compaction, optional LlmCompaction, loop detectionContext management
Sessions, skills, structured outputBranching 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 guardDecision models
Cost and telemetryOpt-in pricing (nothing priced by default); SessionStats per run incl. sub-agents; tracing spans with tokens and costPricing · 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 WorkersWebAssembly & 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.

ExampleWhat it showsKey needed
cliA ~400-line coding agent — all tools, skills, streaming, colored output. Like a baby Claude Codeoptional¹
rlmAn LLM that explores a codebase on its own by spawning sub-agentsyes
code_reviewThree sub-agents reviewing a diff in parallel, results mergedyes
shared_statePassing a large artifact between sub-agents by referenceyes
sub_agentDelegation basics with a per-sub-agent modelyes
basicThe smallest possible agentyes
callbacksLifecycle hooks and a custom toolno
persistenceSave and restore a sessionno
telemetrytracing spans with token and cost fieldsno
gasp_emitRecording a run into a GASP repono
decisionDecision-model questions in one line, and attaching a model to an agent (feature decision)yes
extension_policy, _redact, _verifier, _budget, _tree, _auditExtensions: 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

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.

agent
agent-framework
ai
ai-agents
anthropic
claude
coding-agent
gemini
llm
llm-agent
mcp
openai
rust
streaming
tool-calling

Project health

crates.io

Latest release

0.25.2 · Oct 9, 2026

Releases this year

55

Significant stargazers

Max Bernstein

640 followers · starred Mar 2026

lefarcen

170 followers · starred Apr 2026

Igor Latkin

42 followers · starred Oct 2026

Paulo Suzart

87 followers · starred Oct 2026