Skip to content

Participant types

A participant is the atomic unit of work in a duckflux workflow. Each participant has a type that determines how it executes. All participants share a set of common fields, and each type adds its own specific fields on top.


These fields are available on every participant type:

FieldTypeDefaultDescription
typestringRequired. The participant type (exec, http, mcp, workflow, emit).
asstringDisplay name. Required for reusable participants; optional for inline ones. Enables output reference by name.
timeoutdurationfrom defaultsMaximum execution time. Treated as a failure when exceeded.
onErrorstringfailError handling strategy. See Error Handling.
retryobjectRetry configuration. Only applies when onError: retry.
inputstring or objectExplicit input mapping via CEL expressions. See Inputs & Outputs.
outputobjectOutput schema (JSON Schema, opt-in).

Runs a shell command in the host environment. Use this for builds, tests, linting, deployments, or any operation that can be expressed as a terminal command.

FieldTypeDescription
runstringRequired. The shell command to execute.
cwdstringWorking directory. Supports CEL expressions.
participants:
build:
type: exec
run: npm run build

The cwd field accepts either a literal path or a CEL expression. Precedence for working directory resolution:

participant.cwd > defaults.cwd > CLI --cwd > process cwd

Sends an HTTP request to an external URL. Use this for API integration, webhooks, and external service calls.

FieldTypeDescription
urlstringRequired. Target URL. Supports CEL expressions.
methodstringHTTP method: GET, POST, PUT, PATCH, DELETE.
headersobjectHTTP headers. Values support CEL expressions.
bodystring or objectRequest body. Supports CEL expressions.
participants:
fetchStatus:
type: http
url: https://api.example.com/status
method: GET

Delegates a task to an MCP (Model Context Protocol) server. Use this to invoke tools exposed by external MCP servers or integrations.

FieldTypeDescription
serverstringRequired. MCP server identifier.
toolstringRequired. MCP tool name to invoke.
participants:
codeReviewer:
type: mcp
server: claude
tool: code_review
input:
code: coder.output
language: workflow.inputs.language
flow:
- coder
- codeReviewer

References another duckflux workflow file as a step. Use this to compose large workflows from smaller, reusable pieces.

FieldTypeDescription
pathstringRequired. Path to the sub-workflow YAML file, resolved relative to the parent workflow’s directory.
participants:
reviewCycle:
type: workflow
path: ./review-loop.yaml
input:
repo: workflow.inputs.repoUrl
branch: workflow.inputs.branch
flow:
- coder
- reviewCycle
- deploy

The sub-workflow’s output is accessible as reviewCycle.output in the parent. onError and timeout from the parent apply to the sub-workflow as a whole.

See Nested Workflows for full composition semantics.


Publishes an event to the workflow’s event hub. Use this to broadcast state changes, trigger external listeners, or communicate between parallel branches.

FieldTypeDescription
eventstringRequired. Event name to emit.
payloadstring or objectEvent payload. A single CEL expression or a map of CEL expression values.
ackbooleanIf true, blocks until the event hub confirms delivery. Default: false.

By default, emit dispatches the event and continues immediately:

- as: notify
type: emit
event: "build.started"
payload: build.output

With ack: true, the step blocks until delivery is confirmed. Combine with timeout to cap the wait:

- as: notifyCritical
type: emit
event: "deploy.started"
payload: deploy.output
ack: true
timeout: 10s
onError: skip

A single CEL expression (passes the value directly):

payload: coder.output

A structured object with CEL expression values:

payload:
taskId: workflow.inputs.taskId
status: coder.output.status
startedAt: execution.startedAt

You want to…Use
Run a shell command, script, or CLI toolexec
Call an external API or send a webhookhttp
Invoke a tool on an MCP servermcp
Reuse a workflow from another fileworkflow
Broadcast an event to listenersemit

A pipeline combining all five participant types:

id: full-pipeline
name: Full Pipeline
version: "1"
defaults:
timeout: 10m
inputs:
repoUrl:
type: string
required: true
branch:
type: string
default: "main"
participants:
# exec — run tests locally
runTests:
type: exec
run: npm test
timeout: 5m
onError: fail
# http — fetch external config
fetchConfig:
type: http
url: '"https://config.example.com/apps/" + workflow.inputs.branch'
method: GET
headers:
Authorization: '"Bearer " + env.CONFIG_TOKEN'
# mcp — delegate code review to an MCP tool
codeReview:
type: mcp
server: claude
tool: review_pull_request
input:
repo: workflow.inputs.repoUrl
branch: workflow.inputs.branch
# workflow — run deployment as a sub-workflow
deploy:
type: workflow
path: ./deploy.flow.yaml
input:
repo: workflow.inputs.repoUrl
# emit — notify on completion
notifyComplete:
type: emit
event: "pipeline.completed"
payload:
branch: workflow.inputs.branch
testStatus: runTests.status
reviewApproved: codeReview.output.approved
ack: true
timeout: 5s
onError: skip
flow:
- fetchConfig
- parallel:
- runTests
- codeReview
- deploy:
when: runTests.status == "success" && codeReview.output.approved == true
- notifyComplete
output:
testStatus: runTests.status
reviewApproved: codeReview.output.approved
deployStatus: deploy.status