NATS · durable · multi-agent
stiggy deploys multi-agent architectures on NATS. Describe a fleet once, in YAML or Go: agents, crews, supervisors and swarms run as durable, event-sourced workflows on JetStream. Crews, supervisors, swarms, human review and replay, on a substrate that scales out.
stiggy adds no engine and no agent loop of its own. It compiles a fleet into packtrail flows and runs each agent step with a phero agent, inside a packtrail worker.
Executions are event-sourced on JetStream. Retries, timers, budgets, fork, rerun and time travel come from packtrail, and work on agent steps.
Any phero LLM provider, tool, memory backend or vector store, plus MCP servers. A fresh agent runs per job, with usage reported on every outcome.
The stiggy binary reads YAML; the Go library takes options. Both produce the same fleet, validated and compiled the same way.
stiggy opens one connection and hands it to phero and packtrail. A guard test fails the build if stiggy code touches NATS directly.
A fleet declares models, tools, agents and, to wire them,
crews, patterns or hand-written flows. Decoding is strict, and
stiggy validate reports every problem at once, with its line.
namespace: newsroom models: fast: {provider: ollama, model: gemma4:cloud} agents: researcher: {model: fast, role: Researcher, goal: "Find accurate, recent facts."} writer: {model: fast, role: Writer, goal: "Write short, clear articles."} crews: article: tasks: - {id: research, agent: researcher, description: "Research {{.input.topic}}."} - {id: write, agent: writer, description: Write a 200-word article from the research.}
Crews and patterns are macros. stiggy compile prints the flows and workers they become,
so nothing is hidden.
$ stiggy compile fleet.yaml # worker agent-researcher runs agent researcher # worker agent-writer runs agent writer name: article start: research nodes: - id: research type: task kind: agent-researcher next: write - id: write type: task kind: agent-writer
Pick the level you need. Every one of them ends up as a flow, so retries, budgets, human review and replay work the same everywhere.
| Shape | Section | What you get |
|---|---|---|
| Crew | crews: | Sequential or hierarchical tasks, context, async, guardrails, human_input |
| Supervisor | patterns: | A boss agent routes work to workers until done |
| Swarm | patterns: | Agents hand off to one another |
| Evaluator-optimizer | patterns: | Generate, critique, revise, for up to max_rounds |
| Debate | patterns: | Debaters argue for rounds; a judge decides |
| Plan-execute | patterns: | A planner splits the job, executors run in parallel, a synthesizer merges |
| Your own graph | flows: | Choices, fan-out/join, maps, subflows, waits, agent-chosen routes |
Agents can pause for a human with ask_human, steer the flow with route_to_<node>
tools, return structured output, delegate to other agents (or to remote ones), and keep memory per
execution, which stays correct under fork and rerun.
Every process of a deployment runs the same fleet file and picks its part with -role.
The same binary starts executions and operates them.
nats-server -js & stiggy validate fleet.yaml stiggy run fleet.yaml & # engine + workers in one process stiggy start -ns newsroom -input '{"topic": "NATS"}' -wait article # in production: split the roles and scale the workers stiggy run -role engine -http :8080 fleet.yaml stiggy run -role workers -http :8080 fleet.yaml stiggy run -role workers -only researcher,writer fleet.yaml # operate executions stiggy get | history | progress | signal | resume | update | cancel | fork | rerun
stiggy.New validates and compiles without I/O. Run starts the engine and workers;
Client() is a packtrail client.
nc, _ := nats.Connect(nats.DefaultURL) app, _ := stiggy.New(nc, stiggy.WithNamespace("newsroom"), stiggy.WithModel("fast", openai.New("ollama", openai.WithBaseURL(openai.OllamaBaseURL), openai.WithModel("gemma4:cloud"))), stiggy.WithAgent("researcher", spec.Agent{Model: "fast", Role: "Researcher"}), stiggy.WithAgent("writer", spec.Agent{Model: "fast", Role: "Writer"}), stiggy.WithCrew("article", spec.Crew{Tasks: []spec.Task{ {ID: "research", Agent: "researcher", Description: "Research {{.input.topic}}."}, {ID: "write", Agent: "writer", Description: "Write a 200-word article."}, }}), ) go app.Run(ctx) <-app.Ready() id, _ := app.Client().Start(ctx, "article", map[string]any{"topic": "NATS"}) st, _ := app.Client().Wait(ctx, id)
Six runnable examples ship in examples/, and they double as tests: scripted models by default,
a real one with make examples-live. Requires Go 1.26.4 and a NATS server with JetStream.
go install github.com/henomis/stiggy/cmd/stiggy@latest go run ./examples/router make check # race tests + examples + lint + vet