Skip to main content
Linear chains break down once you need branching, loops, or human-in-the-loop. Graph<S> is Cognis’ answer: a stateful workflow where each step is a node that reads typed state and decides what happens next. Pregel-style execution, generic over your state struct.

What it is

A graph has three parts:
  • State — a struct of yours that travels between nodes. You implement GraphState, which says how an Update is applied to the state.
  • Nodes — async functions that read the state and emit NodeOut { update, goto }.
  • A start node — declared with .start_at("name"). The engine walks edges from there until a node returns Goto::end().
The compiled graph is itself a Runnable<S, S>, so it composes with everything else.

When to reach for a graph

  • You need a tool-calling loop with custom termination logic.
  • You want time travel — checkpoint after every step, rewind, branch.
  • You need human-in-the-loop pauses at specific points.
  • Branches need to run in parallel and rejoin.
  • You want to subgraph and namespace state.
For a plain “model + tools + loop” agent, AgentBuilder is faster — it builds the graph for you. Drop down to graphs when the agent shape isn’t enough.

Quick example

A graph that increments a counter until it hits 5:
node_fn::<S, _, _>(name, async closure) wraps an async closure into a Node<S>. The closure receives (&S, &NodeCtx) and returns Result<NodeOut<S>>.

State and reducers

Two ways to define state.
Spell out how updates apply. Most explicit; works everywhere.

Control flow

Nodes pick the next step by returning a Goto: You can also declare static edges and skip the routing logic in the node:

How it works

  • Each invoke is a sequence of supersteps. The engine runs all eligible nodes in a step, applies their updates atomically, then advances.
  • Goto::Multiple triggers parallel fan-out. All targets run in the same superstep.
  • State is applied, not replaced. Your apply(&mut self, Update) controls how. Reducers are just apply written for one field at a time.
  • Compiled graphs are Runnable<S, S>. Wrappers (with_retry, with_timeout) and observability work the same as anywhere else.

Beyond the basics

See also

Agents and the loop

The shape AgentBuilder compiles into.

Control flow

Fan-out, conditional edges, subgraphs.

Reference → cognis-graph

Full API surface.