github.com/arbazkhan971/graphgo

Durable AI agent workflows for Go β€” a LangGraph-style engine with checkpoints, tools, memory, and local LLMs. One static binary.


Keywords
agents, ai-agents, anthropic, durable-execution, go, golang, langgraph, llm, mcp, ollama, openai, state-machine, workflow-engine
License
MIT
Install
go get github.com/arbazkhan971/graphgo

Documentation

πŸ•ΈοΈ GraphGo

Durable AI agent workflows for Go

Build durable AI agents in Go β€” a LangGraph-style workflow engine with checkpoints, tools, memory, and local-LLM support. One static binary. Typed state. Production-first.

Go Reference Go Report Card CI License: MIT Release


GraphGo lets you model an AI agent as a graph of nodes and edges β€” with cycles, conditional routing, retries, tools, and human approvals β€” and runs it on a durable engine that checkpoints every step. Define workflows in YAML or the typed Go SDK, ship them as a single static binary, and resume, replay or inspect any run.

β–· workflow "support-triage"  β€’  provider=mock  β€’  store=~/.graphgo/checkpoints.db

β–Ά run support-triage (run_369d2a11e978a6fb)
  ● classify
    βœ“ done 0s
    ⛃ checkpoint ckpt_c1057f65
    β†’ classify ─▢ technical  [technical]
  ● technical
    βœ“ done 0s
    ⛃ checkpoint ckpt_38ae22a7
    β†’ technical ─▢ end
βœ” run completed

● status=completed steps=2 run=run_369d2a11e978a6fb

Why GraphGo?

  • 🧩 LangGraph-style, native Go β€” nodes, edges, conditional routing, and cycles with compile-time typed state (Go generics), not stringly-typed dicts.
  • πŸ’Ύ Durable by default β€” every super-step is checkpointed to in-memory or SQLite (pure-Go, no CGO). Crash, resume, and continue.
  • ⏸️ Human-in-the-loop β€” pause a run for approval, persist it, and resume β€” even in a different process.
  • πŸ› οΈ Tools & agents β€” a ReAct-style agent loop with a tool registry whose schema is MCP- and OpenAI-compatible.
  • πŸ”Œ Any model β€” OpenAI, Anthropic, Gemini, Ollama / local models, any OpenAI-compatible endpoint, plus a deterministic mock for tests.
  • πŸ“œ YAML or Go β€” prototype in YAML, or drop into the typed SDK. Same engine underneath.
  • πŸ“¦ One binary β€” graphgo run workflow.yaml. No Python, no runtime, no services. Cross-compiles everywhere.
  • πŸ” Observability β€” streaming execution logs, time-travel replay, run history, and Mermaid/SVG diagram export.

Install

# Go 1.22+
go install github.com/arbazkhan971/graphgo/cmd/graphgo@latest

# Homebrew
brew install arbazkhan971/tap/graphgo

# Docker
docker run --rm ghcr.io/arbazkhan971/graphgo:latest version

# From source
git clone https://github.com/arbazkhan971/graphgo && cd graphgo && make install

60-second quickstart

graphgo init my-agent          # scaffold a starter workflow.yaml
cd my-agent
graphgo run workflow.yaml      # runs offline with the mock provider β€” no API key needed
graphgo visualize workflow.yaml # print a Mermaid diagram

Point it at a real model by exporting a key and selecting a provider:

export OPENAI_API_KEY=sk-...
graphgo run workflow.yaml --provider openai --model gpt-4o-mini

# or fully local, no keys:
graphgo run workflow.yaml --provider ollama --model llama3.2

Define a workflow in YAML

# research-agent.yaml
workflow:
  name: research-agent
  state:
    topic: string
    notes: array
    answer: string
  nodes:
    research:
      type: llm
      system: "You are a meticulous research assistant."
      prompt: "Research {{topic}}. Produce 3-5 key facts as short notes."
      output: notes
      append: true
    review:
      type: human_approval          # pauses for human approval
      message: "Approve the notes for '{{topic}}'?"
    final:
      type: llm
      prompt: "Write a clear answer about {{topic}} using: {{notes}}"
      output: answer
  edges:
    - { from: start,    to: research }
    - { from: research, to: review }
    - { from: review,   to: final }
    - { from: final,    to: end }
graphgo run research-agent.yaml --set topic="graph databases"

…or in the typed Go SDK

package main

import (
	"context"
	"fmt"

	graphgo "github.com/arbazkhan971/graphgo"
)

type State struct {
	Topic  string `json:"topic"`
	Answer string `json:"answer"`
}

func main() {
	g := graphgo.NewGraph[State]()

	g.AddNode("write", graphgo.LLMNode(graphgo.LLMConfig[State]{
		Provider: graphgo.NewMock("Graphs model relationships as nodes and edges."),
		System:   "You are concise.",
		Prompt:   func(s State) string { return "Explain " + s.Topic },
		Apply:    func(s State, r *graphgo.Response) (State, error) { s.Answer = r.Content; return s, nil },
	}))
	g.SetEntryPoint("write")
	g.SetFinishPoint("write")

	res, _ := g.Run(context.Background(), State{Topic: "graph theory"})
	fmt.Println(res.State.Answer)
}

Conditional edges and cycles are first-class:

g.AddConditionalEdge("research", func(_ context.Context, s State) string {
	if len(s.Notes) >= 3 {
		return "done"
	}
	return "more"
}, map[string]string{"more": "research", "done": "write"}) // loops back to research

Visualize

graphgo visualize code-review.yaml emits a GitHub-renderable Mermaid diagram (or JSON / SVG with -f):

flowchart TD
    analyze[["analyze"]]
    triage{"triage"}
    escalate{{"escalate"}}
    report[["report"]]
    start(("start"))
    end(("end"))

    start --> analyze
    analyze --> triage
    triage -.->|high| escalate
    triage -.->|low| report
    escalate --> report
    report --> end

    classDef llm fill:#ede7f6,stroke:#4527a0,color:#311b92;
    classDef human fill:#fff3e0,stroke:#e65100,color:#bf360c;
    classDef router fill:#fce4ec,stroke:#ad1457,color:#880e4f;
    classDef terminal fill:#eceff1,stroke:#455a64,color:#263238;
    class analyze llm;
    class triage router;
    class escalate human;
    class report llm;
    class start terminal;
    class end terminal;
Loading

Durability: checkpoint, resume, replay

Every step is checkpointed, so runs survive crashes and can be paused/resumed:

# A workflow with a human_approval node pauses and persists:
graphgo run research-agent.yaml --set topic="rust"
#   ⏸ paused for approval: Approve the notes for 'rust'?
#   resume with: graphgo run research-agent.yaml --resume run_ab12 --approve

graphgo run research-agent.yaml --resume run_ab12 --approve   # continues to completion

graphgo inspect                 # list every run and its status
graphgo replay run_ab12 --state # time-travel through each step's state

In Go, the same durability is one option away:

store, _ := graphgo.OpenSQLite("runs.db")
res, _ := g.Run(ctx, initial, graphgo.WithStore(store), graphgo.WithRunID("job-42"))
if res.Interrupted() {
	// ...later, even in another process:
	res, _ = g.Resume(ctx, store, "job-42", graphgo.Decision{Approved: true})
}

Node types

Type YAML type SDK builder Purpose
LLM llm LLMNode Prompt a model and write the result to state
Agent (SDK) AgentNode ReAct-style loop that calls tools until done
Tool tool ToolNode Deterministically invoke one tool
Router router LLMRouter / AddConditionalEdge Branch on state or an LLM decision
Human approval human_approval HumanApprovalNode Pause for human input, then resume
Parallel parallel ParallelNode Fan out concurrent branches and merge
Retryable task task (+retry) WithRetry Any node with an automatic retry policy

Providers

Provider Constructor Env var Notes
OpenAI graphgo.OpenAI(...) OPENAI_API_KEY Also any OpenAI-compatible server via BaseURL (vLLM, LM Studio, Together, Groq…)
Anthropic graphgo.Anthropic(...) ANTHROPIC_API_KEY Claude Messages API, tool use
Gemini graphgo.Gemini(...) GEMINI_API_KEY Google Generative Language API
Ollama graphgo.Ollama(...) – Local models, no key, streaming
Mock graphgo.NewMock(...) – Deterministic, offline β€” powers the test suite

CLI

Command Description
graphgo init [dir] Scaffold a starter workflow.yaml
graphgo run <file.yaml> Run a workflow, streaming and checkpointing each step
graphgo visualize <file.yaml> Export Mermaid (-f mermaid|json|svg)
graphgo replay <run-id> Time-travel through a past run's checkpoints
graphgo inspect [run-id] List runs, or show one run's history and final state
graphgo new <name> Scaffold a Go SDK agent program
graphgo doctor Check environment and provider configuration
graphgo version Print the version

Global flags: --provider, --model, --base-url, --store (memory or a path), --no-color.

How does it compare?

GraphGo LangGraph (Python) Temporal Hand-rolled Go
Language Go Python Go/Java/… Go
Deployment single binary Python runtime server + workers your call
Typed state βœ… generics ⚠️ dict/schema βœ… βœ…
Graph + cycles βœ… βœ… ⚠️ code ⚠️ DIY
Checkpoints / resume βœ… βœ… βœ… ❌
Human-in-the-loop βœ… βœ… ⚠️ signals ❌
Built-in LLM providers βœ… βœ… ❌ ❌
YAML workflows βœ… ❌ ❌ ❌
Local-model friendly βœ… ⚠️ ⚠️ ⚠️

GraphGo borrows LangGraph's excellent mental model (stateful graphs for long-running agents) and Temporal's durability mindset (checkpoint, replay, recover), and delivers them as one dependency-light Go module.

Benchmarks

Single core, Intel Xeon @ 2.20GHz, Go 1.22:

Benchmark Time/op Allocs/op
3-node linear graph 4.3 Β΅s 11
3-node linear + checkpoint each step 14.8 Β΅s 29
10-iteration conditional cycle 8.6 Β΅s 25

That's ~230,000 graph runs/sec with zero overhead beyond your node logic. Run them yourself with make bench.

Architecture

cmd/graphgo        the CLI
graphgo.go         the ergonomic SDK facade (NewGraph, LLMNode, HumanApprovalNode, …)
pkg/graph          the execution engine: nodes, edges, cycles, events, retries, interrupts
pkg/state          dynamic Dict state + templating for YAML workflows
pkg/checkpoint     Store interface + in-memory and SQLite backends
pkg/llm            provider interface + OpenAI / Anthropic / Gemini / Ollama / Mock
pkg/tools          tool registry + built-ins (calculator, http_get, now)
pkg/runtime        streaming console printer + time-travel replay
pkg/visualize      Mermaid / JSON / SVG exporters
pkg/workflow       YAML workflow parser and graph builder
examples           runnable YAML workflows and Go SDK programs

Examples

Roadmap

  • Streaming token output surfaced through node events
  • First-class MCP client (connect to any MCP tool server)
  • Postgres checkpoint store
  • Subgraphs / nested graphs as nodes
  • Long-term memory store (vector-backed)
  • Web UI for run inspection and replay
  • State reducers / channels for merge-heavy parallelism

See an issue or open one to shape it.

Contributing

Contributions are very welcome β€” see CONTRIBUTING.md. In short:

go test ./...     # everything runs offline with the mock provider
make lint         # golangci-lint
make bench        # benchmarks

License

MIT Β© 2026 Arbaz Khan.

If GraphGo helps you build something, consider giving it a ⭐ β€” it genuinely helps.