Quack. Define. Execute. Star on GitHub

Declarative
Workflow DSL
for 

Define complex multi-agent pipelines in YAML. Let LLMs do creative work. Let duckflux handle the plumbing.

YAML-native Google CEL State machine Multi-runtime Agent-first Open source
duckflux logo
# hello-world.duck.yaml
name: hello-world

participants:
  greet:
    type: exec
    command: echo "Hello from duckflux! πŸ¦†"

steps:
  - run: greet
scroll

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.

Type-safeSandboxedNo side effectsFast evaluationKubernetes-provenHuman-readable
workflow.duck.yaml
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 reference
example.duck.yaml
participants:
  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

v0.1.0 stable
# 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

v0.1.0 beta
# 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 guide

How 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
βœ“ βœ“ βœ“ βœ“ βœ—
βœ“ Supported βœ— Not supported β—‘ Partial / plugin required

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