Declarative
Workflow DSL
for
Define complex multi-agent pipelines in YAML. Let LLMs do creative work. Let duckflux handle the plumbing.
# hello-world.duck.yaml
name: hello-world
participants:
greet:
type: exec
command: echo "Hello from duckflux! π¦"
steps:
- run: greet Design Philosophy
duckflux isn't another "AI framework". It's an opinionated workflow engine with clear rules about what belongs where.
Declarative-first
Describe what your workflow should do, not how to do it. YAML is the source of truth β readable, version-controlled, diffable.
Deterministic
A state machine β not an LLM β controls flow. Your pipeline runs the same way every time. No hallucinated next steps.
Multi-runtime
Run workflows with the Go CLI for production deployments or the Bun JS/TS runtime for Node.js ecosystems. Same YAML, any runtime.
Powered by CEL
Google Common Expression Language for all conditional logic. Type-safe, sandboxed, and battle-tested in Kubernetes.
Agent-native
Built from the ground up for AI agent orchestration. Participants can call LLMs, MCP tools, HTTP APIs, or shell commands.
Human-readable
YAML you can read in a code review. Self-documenting workflows that any engineer can understand without a PhD in distributed systems.
Features
From simple scripts to complex multi-agent pipelines β duckflux speaks the same YAML regardless of complexity.
Loops
Iterate over collections with `for` loops. Process each item through a participant or nested sub-workflow.
steps:
- for:
var: item
in: "{{ inputs.items }}"
steps:
- run: process_item
input: item
output: "results[item.id]" Parallel execution
Run multiple participants concurrently and synchronize results. Fan-out, fan-in β built into the DSL.
steps:
- parallel:
- run: agent_a
output: result_a
- run: agent_b
output: result_b
- run: agent_c
output: result_c
- run: aggregator
input: [result_a, result_b, result_c] Conditionals
CEL-powered `when` guards on any step. Route execution based on previous outputs, inputs, or context.
steps:
- run: analyze
output: analysis
- run: handle_success
when: "analysis.score >= 0.8"
- run: handle_failure
when: "analysis.score < 0.8"
input: analysis.reason Guards & retry
Automatic retry with configurable backoff, max attempts, and CEL conditions. Guards prevent steps from running when prerequisites aren't met.
steps:
- run: reviewer
output: review
retry:
max: 3
delay: 2s
when: "!review.approved"
on_error: handle_review_error Events
Emit events to named channels and pause execution waiting for external events. Perfect for human-in-the-loop workflows.
steps:
- run: draft_code
output: draft
- emit:
channel: "approvals"
data: { draft: draft, author: inputs.user }
- wait:
event: "approval.received"
timeout: 24h
output: decision
- run: deploy
when: "decision.approved == true" Input/Output schemas
Typed inputs and outputs with validation. CEL expressions reference inputs and previous outputs by name β fully type-aware.
inputs:
repo:
type: string
required: true
branch:
type: string
default: "main"
dry_run:
type: boolean
default: false
outputs:
deploy_url:
type: string
exit_code:
type: integer Nested workflows
Compose complex pipelines from smaller reusable sub-workflows. Pass context down and collect results back up.
participants:
test_suite:
type: workflow
path: ./workflows/test-suite.duck.yaml
deploy:
type: workflow
path: ./workflows/deploy.duck.yaml
steps:
- run: test_suite
input: "{{ context }}"
output: test_results
when: "!inputs.skip_tests" Error handling
Declare error handlers per-step or globally. Capture, transform, or re-raise errors using CEL expressions.
steps:
- run: risky_operation
output: result
on_error:
run: error_handler
input:
error: "{{ error }}"
context: "{{ context }}"
on_failure:
- run: notify_slack
input: "{{ error }}" Powered by Google CEL
Google's Common Expression Language keeps your logic safe, predictable, and readable. The same engine that powers Kubernetes admission controllers.
steps:
- run: analyze
output: result
- run: approve
when: "result.score >= 0.9 && result.issues.size() == 0"
- run: review
when: "result.score >= 0.6 && result.score < 0.9"
- run: reject
when: "result.score < 0.6" CEL expressions used
result.score >= 0.9 Direct field access with comparison
result.issues.size() == 0 CEL built-in: list length check
&& Boolean AND β both conditions must be true
Building Blocks
Every step in a duckflux workflow is powered by a participant. Six types cover everything from shell commands to event-driven coordination.
exec Shell commands & scripts
Execute any shell command, script, or binary. Perfect for AI agent CLIs, build tools, or custom runners.
Full exec referenceparticipants:
coder:
type: exec
command: >
claude --model claude-opus-4-5
--prompt "{{ inputs.task }}"
--output-format json Same YAML, any Runtime
One workflow definition runs anywhere. Use the Go CLI for production and edge deployments, or the JS/TS runtime to integrate with your Node/Bun ecosystem.
Go CLI
Production-ready binary
# Install with Go
go install github.com/your-org/duckflux/cmd/duck@latest
# Or download binary
curl -sSL https://install.duckflux.dev | sh
# Run a workflow
duck run ./my-workflow.duck.yaml
# Run with inputs
duck run ./pipeline.duck.yaml \
--input repo=https://github.com/org/repo \
--input branch=main
# Watch mode
duck run ./pipeline.duck.yaml --watch JS/TS (Bun)
Bun & Node.js compatible
# Install with Bun
bun add -g duckflux
# Or with npm / pnpm
npm install -g duckflux
pnpm add -g duckflux
# Run a workflow
duck run ./my-workflow.duck.yaml
# Use as library in your Bun app
import { run } from 'duckflux';
const result = await run('./pipeline.duck.yaml', {
inputs: { repo: 'https://github.com/org/repo' }
}); Not sure which to choose?
Read the runtime comparison guideHow duckflux Compares
An honest comparison with popular workflow orchestration tools. Different tools solve different problems β here's where duckflux fits.
| Feature | duckflux YAML DSL for agents | Temporal Workflow platform | LangGraph LLM graph orchestration | n8n Visual automation | Step Functions AWS managed workflows |
|---|---|---|---|---|---|
| YAML DSL Define workflows in human-readable YAML | β | β | β | β | β |
| Agent-native First-class support for AI agent orchestration | β | β | β | β | β |
| CEL expressions Google CEL for safe, typed condition evaluation | β | β | β | β | β |
| Multi-runtime Run on multiple language runtimes | β | β | β | β | β |
| MCP support Native Model Context Protocol integration | β | β | β | β | β |
| Loops Iterate over collections natively | β | β | β | β | β |
| Parallel steps Fan-out parallel execution | β | β | β | β | β |
| Event wait Pause execution for external events | β | β | β | β | β |
| Self-hosted Run on your own infrastructure | β | β | β | β | β |
| Open source Fully open-source license | β | β | β | β | β |
Comparison based on publicly available documentation. Table reflects capabilities, not quality.
Ready to quack?
Stop orchestrating
imperatively.
Write your first workflow in 5 minutes. Run it with a single command. Let duckflux handle the state machine so you can focus on what matters.
$ duck run ./hello.duck.yaml