agent-kernel
Minimal Rust kernel for multi-agent LLM discussion. One trait, one function, full observability.
Quick Start
Step 1 — Add the dependency:
[]
= "0.1"
= { = "1", = ["full"] }
= "0.7"
= "1"
Step 2 — Implement AgentRuntime:
use ;
Step 3 — Call discuss():
use ;
use mpsc;
use CancellationToken;
async
See examples/simple_discussion.rs for a runnable version with a MockRuntime.
Architecture
┌─────────────────────────────────────────────────┐
│ Product shell (your app) │
│ │
│ Discord Bot │ HTTP API │ CLI │ Tests │
└───────────────────────┬─────────────────────────┘
│ depends on
┌───────────────────────┴─────────────────────────┐
│ agent-kernel (this crate) │
│ │
│ Agent struct AgentRuntime trait │
│ discuss() AgentEvent stream │
│ Message/Role EvolutionRuntime trait │
│ │
│ deps: tokio(sync) + futures + anyhow │
│ NOT included: axum / serenity / reqwest / │
│ rusqlite / serde / clap │
└─────────────────────────────────────────────────┘
│ implements
┌───────────────────────┴─────────────────────────┐
│ LLM Provider (your impl) │
│ │
│ Anthropic │ OpenAI │ OpenRouter │ Ollama │
└─────────────────────────────────────────────────┘
Kernel boundary rule: agent-kernel depends only on tokio (sync feature), futures, anyhow, and tokio-util. Everything else belongs in the product shell.
Design principles (inherited from pi-mono):
| Principle | How it applies here |
|---|---|
| Extreme minimalism | AgentRuntime has exactly 1 method; discuss() is the only orchestration primitive |
| Full trust | Caller passes rounds: usize directly — no policy wrapper |
| Observability first | AgentEvent is a first-class output via mpsc::Sender |
| Late binding | Message stays in kernel format until your respond() converts it |
| Persistent self-evolution | EvolutionRuntime trait — feedback, memory, SOUL.md iteration as kernel primitives |
API Reference
Agent
SOUL.md is the sole configuration source for an agent. No built-in role or persona concept.
AgentRuntime
Implement this to connect the kernel to any LLM provider. See examples/custom_runtime.rs for the full pattern.
discuss()
pub async
The only orchestration primitive. Runs exactly rounds rounds — no convergence logic (caller decides policy). agents[0] is the primary agent and produces the final summary. Returns the primary agent's last response.
AgentEvent
Emitted via the mpsc::Sender during a discussion:
| Variant | When |
|---|---|
Progress { current_round, max_rounds } |
Start of each round |
Round { round, agent_name, content } |
Each agent's response |
Converged { reason } |
Reserved for future convergence detection |
Summary { content } |
Final summary from agents[0] |
Cancelled |
CancellationToken was triggered |
Completed |
All rounds finished |
Evolved { agent, old_version, new_version } |
SOUL.md was evolved (Phase 2) |
Message and Role
Internal message format. Convert to your provider's format inside AgentRuntime::respond().
EvolutionRuntime (Phase 2)
Persistent self-evolution primitives. Implement in your product shell to wire up feedback scoring, memory storage, SOUL.md optimization, and version rollback. The kernel defines the contract; you provide the storage and LLM calls.
BoxFuture
pub type BoxFuture<'a, T> = ;
Used as the return type of AgentRuntime::respond() and EvolutionRuntime methods. Avoids the async_trait macro dependency.
Examples
# MockRuntime + 2 agents + 3 rounds
# Pattern for a real HTTP-based runtime
License
Licensed under either of MIT or Apache-2.0 at your option.