newEmbedded clusters, leases and leader election

Durable workflows.
One binary.
Just NATS.

dagnats runs graphs of tasks, agent loops and human approvals. It retries what fails and resumes after a crash, with NATS JetStream embedded in the same process. No Postgres, no Redis, no broker to run.

Get started
go install github.com/danmestas/dagnats/cmd/dagnats@latest

Apache-2.0 · Go · alpha, breaking changes possible

run 9e63…f0bf · nightly-refactorrunning
triggercron
0 3 * * * · fired 03:00:00
done
planplanner
Planned 4 tasks from the issue
done
buildagent_loop
Iteration 3 of 8 · checkpointed
running
testmap
12 shards in parallel
8 / 12
reviewapproval
Waits for a human, times out in 24h
waiting
shiptask
Open the pull request
pending
03:00:00 workflow.started nightly-refactor
03:00:02 step.completed plan 4 tasks
03:04:41 step.started build iter=3
03:04:41 step.queued test[11]
Runtime deps
NATS JetStream, embedded
Deploy artifact
One Go binary
Scales to
3 or 5 node clusters
SDKs
Go, plus an HTTP bridge

Everything a workflow engine needs. Nothing it has to depend on.

State is an event log in JetStream with snapshots in KV. Kill the process, start it again, and in-flight work picks up from the last event.

01

One binary, zero databases

Deploy is scp and serve. No migrations, no Redis to operate, no broker to configure.

02

Crash-safe by default

Every transition is an event in JetStream. A restart replays to the last one and carries on.

03

Agent steps are first-class

AgentLoop, Planner, Approval and WaitForEvent are step types, not patterns you rebuild per project.

04

Inspectable to the byte

Every event is a JSON message on a subject. Tail any run live from any terminal.

05

Bounded everywhere

No unbounded queues, retries or recursion. Every loop has a fixed upper limit.

06

Clusters when you need them

Three or five nodes, every stream replicated, routes over your private network. Leases and leader election built in.

Quickstart

From zero to a running workflow in four commands.

dagnats serve starts NATS, the orchestrator, the API, the console and the trigger system in one process. There is no step five.

$ go install github.com/danmestas/dagnats/cmd/dagnats@latest
$ dagnats serve                  # one process, embedded NATS
$ dagnats workflow register hello.json
$ dagnats run start hello --watch
  ✓ greet      completed  12ms
  ✓ run        completed
How it fits together

All state lives in JetStream and KV. That is the whole system.

01 · triggers
Cron, webhooks, subjects, run-terminal

Each fire becomes an event on the history stream, deduplicated by message ID.

02 · orchestrator
Consume event, advance the DAG, snapshot

Timeouts, sleeps and retries are timers on a stream, not a scheduler you run.

03 · workers
Pull tasks, report results

Go workers in-process or anywhere on NATS; anything else over the HTTP bridge.

JetStream · WORKFLOW_HISTORY · TASK_QUEUES · SLEEP_TIMERS · EVENTS · +5KV · workflow_runs · leases · singleton_locks · +16

Compared to neighbors

dagnatsTemporalHatchetInngest
StackNATS onlyPostgres + CassandraPostgres + RabbitMQPostgres + Redis
Binaries1~5~3hosted
Open sourceyesyesyespartial
Native agent stepsyesnoyesyes
SDKsGo + HTTP bridgemany33
Self-hosttrivialinvolvedmoderaten/a

Open-source distributions as of writing. Approximate; orientation only.

What it is not

dagnats is young and single-tenant by design. There is one Go SDK plus an HTTP bridge; a native TypeScript or Python SDK is yours to write.

Skip it for sub-millisecond task routing (use a queue), for dependency-free batch jobs (use a worker pool), and where eventual consistency would surprise you (use a database with transactions).

Run it before your coffee cools.