name: zenflow description: Multi-agent workflow engine for Go. Declarative YAML workflows; an LLM coordinator routes events through hub-and-spoke mailboxes. Three CLI verbs (flow / goal / agent) cover deterministic execution, dynamic planning, and one-shot agent calls. Use this when you need to run a multi-step LLM pipeline with branching, loops, conditions, retries, or persistence. allowed-tools: Bash
zenflow
zenflow is a multi-agent workflow engine for Go. Workflows are declarative YAML; the engine is a DAG executor with an LLM coordinator that narrates progress and routes events between running steps through race-safe mailboxes. The Go SDK layer is goai - any provider goai supports works as a zenflow agent backend (Google, AWS Bedrock, Azure, OpenAI-compatible).
Install
One-line installer (Linux + macOS):
curl -fsSL https://zenflow.sh/install.sh | sh
Or via go install:
go install github.com/zendev-sh/zenflow/cmd/zenflow@latest
Or pull the Docker image:
docker pull ghcr.io/zendev-sh/zenflow:latest
The single Go binary has no runtime dependencies.
Three CLI verbs
| Command | When |
| --- | --- |
| zenflow flow workflow.yaml | The plan is fixed up-front; you want a deterministic DAG execution. |
| zenflow goal "build a thing" | The plan must adapt to user input; the coordinator decomposes the goal into a workflow on the fly and runs it. |
| zenflow agent "<prompt>" | One-shot agent call with optional tool loop. Reuses zenflow's lifecycle hooks and provider routing. |
zenflow flow - deterministic DAG
zenflow flow review.yaml --model gemini/gemini-3-pro-preview
Loads the YAML, validates, runs every step in dependency order. Failures cascade per options.onStepFailure.
zenflow goal - dynamic planning
zenflow goal "Refactor the auth module to use OAuth2" --model bedrock/anthropic.claude-sonnet-4-6
The coordinator LLM decomposes the goal into a workflow (agents + steps), validates it against the spec schema, and executes. Pass --plan to print the plan without running it.
zenflow agent - single-agent chat
zenflow agent "Summarise this repo's README" --model azure-deployment/gpt-5
A single agent loop with the configured tool catalog. Most useful for one-shot tasks that don't need multi-step coordination.
Provider env vars
Set the credentials for whichever provider you target:
| Provider | Env var | Example model |
| --- | --- | --- |
| Google Gemini | GEMINI_API_KEY | gemini/gemini-3-pro-preview |
| AWS Bedrock | AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY (or AWS profile) | bedrock/anthropic.claude-sonnet-4-6, bedrock/minimax.minimax-m2.5 |
| Azure (AI Services / OpenAI / Anthropic) | AZURE_OPENAI_API_KEY + AZURE_RESOURCE_NAME | azure-deployment/gpt-5, azure-deployment/claude-sonnet-4-6 |
The --model flag accepts the provider/model-id form. For Azure, deployment-based URLs are auto-resolved when the model id matches a known deployment family.
MCP tools
zenflow reads a Claude-compatible .zenflow/settings.json and exposes every declared MCP server's tools to agents. All three verbs use it; override with --mcp-config PATH, disable with --no-mcp.
{ "mcpServers": { "firecrawl": { "command": "npx", "args": ["-y", "firecrawl-mcp"], "env": { "FIRECRAWL_API_KEY": "${FIRECRAWL_API_KEY}" } } } }
Tools are namespaced <server>__<tool>; an agent's tools: list grants a whole server by its bare name (firecrawl) or one tool by its full name (firecrawl__scrape). stdio, HTTP, and SSE transports are supported, with ${VAR} env expansion.
YAML workflow shape
Minimum:
name: my-workflow
agents:
writer:
description: A concise technical writer.
prompt: "Always reply in numbered bullet points."
steps:
- id: draft
agent: writer
instructions: "Draft a 5-point summary of {{.context.input}}."
Add features as you need them:
dependsOn: [otherStep]- DAG edges.condition: steps.draft.result.length > 100- CEL expression; step isskippedwhen false.loop:- three flavours:forEach(iterate an array from a previous step's output),repeat-until(run a sub-DAG until anuntilAgentreturnsdone: trueor auntilCEL expression is true),outputMode: cumulative | last.include: subworkflow.yaml- compose sub-workflows; their step IDs are namespaced under the parent step.tool: read/toolInput: {path: $steps["prev"].content}- invoke a registered goai tool directly (no LLM call). String values intoolInputstarting with$are evaluated as CEL expressions. Available CLI tools:bash,read,write,glob,grep. Mutually exclusive withagent,instructions,loop, andinclude.resultSchema: { ... }- auto-injects asubmit_resulttool so the agent emits structured output.options:-maxConcurrency,onStepFailure: cascade | skip-dependents | abort,timeout,stepTimeout,isolation: worktree-per-step,scheduler: dependency-first | round-robin | least-busy.
Full reference: https://zenflow.sh/yaml.
NDJSON --json event schema
Every CLI verb accepts --json for line-delimited JSON output. Each event line carries:
| Field | Type | Notes |
| --- | --- | --- |
| type | string | Event type (see table below). |
| timestamp | RFC3339 string | Event clock. |
| runId | string | Workflow run ID; correlates events from the same run. |
| stepId | string | Step ID; absent for run-scoped events. |
| agent | string | Agent name; absent for non-agent events. |
| agentId | string | Per-call agent ID (set on streaming output events when the runner is namespaced). |
| message | string | Human-readable detail; semantics differ per event type. |
| duration | string | Go duration string ("1.234s"); set on completion events. |
| tokens | object | {prompt, completion, total} token counts; set on completion events. |
| error | string | Error string; set on failure events. |
| data | object | Event-type-specific payload (input args, output bytes, drop reasons, etc.). |
| delta | string | Streaming token delta. Only on output. |
| done | boolean | Streaming-end marker. Only on output. |
| reasoning | boolean | Set to true when the streaming delta is reasoning/thinking content (vs final agent text). Omitted otherwise. |
Event types
| type | Emitted when |
| --- | --- |
| workflow_start | Workflow run begins. |
| workflow_end | Workflow run ends (success or failure). |
| step_start | A DAG step begins. |
| step_end | A DAG step ends successfully. |
| step_skipped | A step skipped (failed dep with skip-dependents strategy, or false condition). |
| error | A step failed; subsequent dependents may cascade per options.onStepFailure. |
| agent_turn | The agent loop took a turn (LLM call). data.phase is request or response. |
| tool_call | A tool was invoked. data.phase is start or end. |
| message | An informational message (e.g. CEL skip reason, forEach item cap). |
| coordinator_narration | Coordinator's narrate(...) tool call. |
| coordinator_message | Coordinator's forward_to_agent(...) tool call. |
| coordinator_synthesis | Coordinator's finalize(summary=...) tool call. |
| coordinator_inbox_message | Reverse reply from a resumed step landed in the coordinator's inbox. |
| message_sent | An agent or coord-side outbound message was queued. |
| message_dropped | A router message was dropped before delivery. data.reason carries the typed reason. |
| agent_inbox_drain | An agent drained one router message into its LLM conversation. |
| agent_idle | The agent finished a goai iteration with no unread mailbox messages. |
| agent_wake | The agent woke from idle to drain new messages. |
| max_wake_cycles_warning | Wake-cycle cap is at 80% of configured limit. |
| resume_started | Auto-resume goroutine spawned for a terminated step that received a new router message. |
| resume_completed | Resume run finished with a final response. |
| resume_failed | Resume could not complete (ctx cancel, transcript cap, agent error). |
| resume_queued | A resume attempt arrived while another for the same step was already in flight. |
| transcript_sealed | Transcript Append hit the size cap; subsequent appends for the step are suppressed. |
| plan_ready | RunGoal decomposition produced a workflow. data.workflow carries the parsed *Workflow. |
| output | Streaming agent output token. Set delta, done, optionally reasoning. |
The schema is additive: new event types may appear, existing types never reshape. Unknown type values are safe to skip.
Exit codes
| Code | Meaning |
| --- | --- |
| 0 | Success. |
| 1 | Step or workflow failure. |
| 2 | Validation or coordinator-side error. |
| 3 | Configuration or usage error (missing argument, unknown flag, no LLM provider). |
| 124 | Hard-watchdog timeout. Fires when --timeout was set and the process did not unwind within timeout + 30s; goroutine stacks are dumped to stderr. |
When to use which mode
You have a YAML workflow file already. → zenflow flow workflow.yaml
You have a free-form goal in a string. → zenflow goal "<goal>"
You have a one-shot agent prompt. → zenflow agent "<prompt>"
You want deterministic, repeatable runs. → zenflow flow
You want the coordinator to plan on the fly. → zenflow goal
You want to chain steps, conditions, loops. → flow or goal (both support full YAML)
You only need a single LLM call. → zenflow agent
You need to embed in Go code. → import github.com/zendev-sh/zenflow
You need to script around the binary. → use --json output (see schema above)
Embedding in Go
The same engine is exposed as a library:
import (
"context"
"github.com/zendev-sh/zenflow"
"github.com/zendev-sh/goai/google"
)
func run(ctx context.Context) error {
llm, _ := google.New(ctx, "gemini-3-pro-preview")
orch := zenflow.New(
zenflow.WithModel(llm),
zenflow.WithStorage(zenflow.NewMemoryStorage()),
)
defer orch.Close()
wf, err := zenflow.LoadWorkflow("review.yaml")
if err != nil { return err }
result, err := orch.RunFlow(ctx, wf)
_ = result
return err
}
49 With* orchestrator options + 22 WithRunner* agent options cover provider config, concurrency, timeouts, mailbox tuning, transcript caps, isolation, observability, and resume policies. Full reference: https://zenflow.sh/api.
Reference
Expert Next.js App Router
Developpement
Un skill qui transforme Claude en expert Next.js App Router.
Générateur de README
Developpement
Crée des README.md professionnels et complets pour vos projets.
Rédacteur de Documentation API
Developpement
Génère de la documentation API complète au format OpenAPI/Swagger.