Heartbit
Multi-agent enterprise runtime in Rust
Orchestrator spawns sub-agents that execute LLM-powered reasoning loops with parallel tool execution. Zero-copy. Three execution paths. Production-grade.
cargo add heartbit Why Heartbit
Zero-copy Agent Loops
ReAct cycle in pure Rust. No Python or Node overhead. Minimal allocations, maximum throughput.
Three Execution Paths
Standalone (zero infra), Durable (Restate), or Daemon (Kafka). Pick the right path for your workload.
Parallel Tool Execution
tokio::JoinSet runs tools concurrently within each turn. Flat agent hierarchy prevents runaway spawning.
8 Guardrails + Memory
Content fence, injection classifier, PII, tool policy, LLM judge, and more. MemGPT-style memory with hybrid retrieval.
Built-in Eval Framework
Trajectory scoring, keyword matching, and similarity scoring. Test agent behavior with real assertions.
Local-first Embeddings
Offline semantic search via ONNX Runtime (fastembed). No API keys required. Runs entirely on your hardware.
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ heartbit-cli (bin) │
│ Commands: run | chat | serve | daemon | submit | status | approve │
└────────────────────────────────┬────────────────────────────────────┘
│
┌────────────────────────────────▼────────────────────────────────────┐
│ heartbit (lib) │
│ │
│ ┌─────────────────┐ ┌────────────────┐ ┌──────────────────────┐ │
│ │ Standalone │ │ Durable │ │ Daemon │ │
│ │ │ │ │ │ │ │
│ │ AgentRunner │ │ AgentWorkflow │ │ Kafka consumer │ │
│ │ Orchestrator │ │ OrchestratorWf │ │ Axum HTTP API │ │
│ │ tokio::JoinSet │ │ Restate SDK │ │ SSE + WebSocket │ │
│ │ │ │ │ │ Cron scheduler │ │
│ └────────┬─────────┘ └───────┬────────┘ │ Heartbeat pulse │ │
│ │ │ └──────────┬───────────┘ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐│
│ │ Shared Core ││
│ │ ││
│ │ LlmProvider (Anthropic, OpenRouter) Tool trait + MCP client ││
│ │ Memory (InMemory, Postgres) KnowledgeBase ││
│ │ Guardrails (pre/post LLM & tool) Sensor pipeline ││
│ │ Context strategies Channel adapters ││
│ │ Cost tracking + OTel Permission system ││
│ └─────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────┘ Quick Examples
use std::sync::Arc;
use heartbit::{AgentRunner, AnthropicProvider};
let provider = Arc::new(AnthropicProvider::new(api_key, "claude-sonnet-4-20250514"));
let agent = AgentRunner::builder(provider)
.system_prompt("You are a helpful assistant.")
.build()?;
let output = agent.execute("Analyze the Rust ecosystem").await?;
println!("{}", output.result); use std::sync::Arc;
use heartbit::{AnthropicProvider, Orchestrator};
let provider = Arc::new(AnthropicProvider::new(api_key, "claude-sonnet-4-20250514"));
let mut orchestrator = Orchestrator::builder(provider)
.sub_agent("researcher", "Finds facts and data", "You research.")
.sub_agent("writer", "Writes polished prose", "You write.")
.build()?;
let output = orchestrator.run("Write an article about Rust").await?; use heartbit::{Tool, ToolDefinition, ToolOutput};
use serde_json::json;
struct PriceLookup;
impl Tool for PriceLookup {
fn definition(&self) -> ToolDefinition {
ToolDefinition {
name: "price_lookup".into(),
description: "Look up product prices".into(),
input_schema: json!({
"type": "object",
"properties": {
"product": { "type": "string", "description": "Product name" }
},
"required": ["product"]
}),
}
}
fn execute(&self, input: Value) -> Pin<Box<dyn Future<...>>> {
Box::pin(async move {
let product = input["product"].as_str().unwrap_or_default();
Ok(ToolOutput::success(format!("Price: $9.99")))
})
}
} Three Execution Paths
Standalone
No infrastructure
In-process agent execution. CLI tasks, scripts, library embedding. Zero setup.
Durable
Restate server
Crash-resilient workflows with exactly-once tool execution. Survives restarts.
Daemon
Kafka + Axum
Long-running services with HTTP API, cron scheduling, WebSocket, and Telegram.