Built for agents
Agentic workflows that outlive the process.
An agent that plans, calls tools in parallel, waits days for a human and then acts is a
workflow. Dwarf gives you the pieces as graph primitives, and every one of them is durable.
- Loops and routing: cycle through think and act until the goal is met
- Parallel tool calls:
forEach fans out one branch per item, and reducers merge the results - Human-in-the-loop:
Interrupt parks the flow for as long as it takes; Resume picks it up - Subgraphs: call one workflow from another, like a function
- Any LLM: bring the model SDK you already use; a task is just a function
- Time travel:
Fork a closed flow from any of its steps, or Continue a completed flow for the next turn of a conversation

// Plan, search in parallel, merge, get a human's sign-off, book.
g := workflow.NewGraph("TripPlanner")
g.SetURL("Plan", "https://trip/plan")
g.SetURL("Search", "https://trip/search")
g.SetURL("Draft", "https://trip/draft")
g.SetURL("Approve", "https://trip/approve")
g.SetURL("Book", "https://trip/book")
g.AddTransitionForEach("Plan", "Search", "queries", "query") // one branch per query
g.AddTransition("Search", "Draft")
g.SetFanIn("Draft") // waits for every branch
g.SetReducer("findings", workflow.ReducerAppend) // and merges what they found
g.AddTransition("Draft", "Approve")
g.AddTransitionSwitch("Approve", "Book", "approved")
g.AddTransitionSwitch("Approve", "Plan", "!approved") // or plan again
g.AddTransition("Book", workflow.End)
// Approve parks the flow until a human decides, whether that takes minutes or weeks.
func Approve(ctx context.Context, f *workflow.Flow) error {
var decision struct{ Approved bool }
yield, err := f.Interrupt(map[string]any{"question": "Book this itinerary?"}, &decision)
if err != nil || yield {
return err // parked; re-enters on Resume
}
f.SetBool("approved", decision.Approved)
return nil
}