Workflow Create
Author a workflow on whichever surface fits the job.
Pick a surface
- MCP workflow template — a persisted definition with a pause/resume lifecycle. Use for long-lived, human-gated, resumable pipelines.
- Native
.claude/workflows/*.js— an imperative orchestration script that fans subagents out. Use for comprehensive fan-out (review, audit, migration, research) where you aggregate structured results in code.
A — MCP workflow template
- List templates — call
mcp__claude-flow__workflow_templateto see available templates - Create workflow — call
mcp__claude-flow__workflow_createwith steps, conditions, and execution order - List workflows — call
mcp__claude-flow__workflow_listto see all defined workflows - Check status — call
mcp__claude-flow__workflow_statusto monitor a workflow - Clean up — call
mcp__claude-flow__workflow_deleteto remove unused workflows
Features: sequential/parallel steps, conditional branching, template inheritance, pause/resume approval gates.
B — Native .claude/workflows/*.js
Write a .js file under .claude/workflows/. It MUST begin with a pure-literal export const meta block; the body runs inside an async wrapper (top-level await/return are legal) with these hooks injected:
| Hook | Purpose |
|---|---|
agent(prompt, opts) |
Spawn one subagent; pass opts.schema (JSON Schema) to get validated structured output back |
parallel(thunks) |
Run thunks concurrently with a barrier — .filter(Boolean) the results |
pipeline(items, ...stages) |
Stream each item through stages independently — prefer this over a barrier |
phase(title) / log(msg) |
Progress grouping / narration |
export const meta = {
name: 'my-workflow', // becomes the invocable name — must be a pure literal
description: 'one line',
phases: [{ title: 'Find' }, { title: 'Verify' }],
}
const SCHEMA = { type: 'object', required: ['ok'], properties: { ok: { type: 'boolean' } }, additionalProperties: false }
phase('Find')
const found = await agent('find the things', { schema: SCHEMA, agentType: 'tester' })
phase('Verify')
const checked = await parallel((found.items || []).map((it) => () =>
agent(`verify ${it}`, { schema: SCHEMA })))
return { found, checked: checked.filter(Boolean) }
Rules: meta is a pure literal (no variables/calls/interpolation); default to pipeline over parallel; never use Date.now()/Math.random() (they throw — vary by index instead). Validate syntax (the body is ESM-in-async-wrapper, not a bare module):
node -e 'const fs=require("fs");let s=fs.readFileSync(".claude/workflows/my-workflow.js","utf8").replace(/^export\s+const\s+meta/m,"const meta");fs.writeFileSync("/tmp/wf.mjs","let agent,parallel,pipeline,phase,log,args,budget,workflow;async function __wf(){\n"+s+"\n}")' \
&& node --check /tmp/wf.mjs && echo OK
Run it with the workflow-run skill or Workflow({ name: 'my-workflow' }). Reference: .claude/workflows/plugin-contract-audit.js. See ADR-0002.