plugins/ruflo-workflows/skills/workflow-create/SKILL.md
Author a workflow on whichever surface fits the job.
.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.mcp__claude-flow__workflow_template to see available templatesmcp__claude-flow__workflow_create with steps, conditions, and execution ordermcp__claude-flow__workflow_list to see all defined workflowsmcp__claude-flow__workflow_status to monitor a workflowmcp__claude-flow__workflow_delete to remove unused workflowsFeatures: sequential/parallel steps, conditional branching, template inheritance, pause/resume approval gates.
.claude/workflows/*.jsWrite 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.