stiggy.

NATS · durable · multi-agent

Multi-agent systems
that survive crashes.

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.

01Two libraries, glued

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.

Durable by construction

Executions are event-sourced on JetStream. Retries, timers, budgets, fork, rerun and time travel come from packtrail, and work on agent steps.

Agents from phero

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.

One model, two front ends

The stiggy binary reads YAML; the Go library takes options. Both produce the same fleet, validated and compiled the same way.

NATS is the only transport

stiggy opens one connection and hands it to phero and packtrail. A guard test fails the build if stiggy code touches NATS directly.

02One file, one fleet

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.}

It compiles to a plain packtrail flow

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

03Crews, patterns, and raw flows

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.

ShapeSectionWhat you get
Crewcrews:Sequential or hierarchical tasks, context, async, guardrails, human_input
Supervisorpatterns:A boss agent routes work to workers until done
Swarmpatterns:Agents hand off to one another
Evaluator-optimizerpatterns:Generate, critique, revise, for up to max_rounds
Debatepatterns:Debaters argue for rounds; a judge decides
Plan-executepatterns:A planner splits the job, executors run in parallel, a synthesizer merges
Your own graphflows: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.

04Run it, scale it, operate it

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

05Or embed it in Go

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)

06Try it

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

See the examples →