Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

eko-core

A pure state-graph execution engine for building AI agents in Rust.


eko-core does one thing and does it well: drive state through a graph of nodes and edges you define. It contains no LLM calls, no tool implementations, no preset patterns — just the core execution engine.

Features

Pure State GraphDefine nodes, edges, and channels — the engine handles the rest
Deterministic ExecutionSuperstep model guarantees consistent results regardless of parallel task ordering
ChannelsPluggable merge strategies: last-write-wins, custom reducers, ephemeral, queues
Interrupt & ResumeHuman-in-the-loop: pause execution, collect feedback, resume seamlessly
CheckpointsSave and restore graph state at any point for fault tolerance
Fan-out & JoinParallel task dispatch with barrier-based synchronization
SubgraphsCompose graphs — embed a compiled graph as a node in another graph
Retry & TimeoutPer-node retry policies with exponential backoff; per-node timeouts
Derive Macro#[derive(State)] auto-generates channel mappings from struct definitions
Async NativeBuilt on Tokio, fully async from top to bottom

Install

Add to your Cargo.toml:

[dependencies]
eko-core = "0.1"

One-minute Overview

State  = a set of Channel values (the "shared blackboard")
Node   = reads State → does work → writes back to State
Edge   = decides which Node runs next
Graph  = Nodes + Edges + Channels
#![allow(unused)]
fn main() {
use eko_core::*;
use std::collections::HashMap;
use serde_json::json;

// 1. Define channels (merge strategies)
let mut channels = HashMap::new();
channels.insert("msg".into(), Box::new(LastValue::new()) as Box<dyn AnyChannel>);

// 2. Build the graph
let mut g = StateGraph::new(channels);
g.add_node_fn("greet", |mut s, _| async move {
    s.insert("msg".into(), json!("hello world"));
    Ok(NodeOutput::Update(s))
});
g.add_edge(START, "greet");
g.add_edge("greet", END);

// 3. Compile & execute
let compiled = g.compile(CompileConfig::default())?;
let result = compiled.invoke(HashMap::new(), &GraphConfig::default()).await?;
// result = GraphResult::Done { values: {"msg": "hello world"}, .. }
}

What’s Next