Author a new Claude Code Workflow — a deterministic multi-agent orchestration script driven by the Workflow tool (agent / pipeline / parallel / phase / log), where the script, not the model, decides control flow. Use when the user wants to build, create, or design a workflow, fan out subagents over a work-list, pipeline multi-stage agent work, adversarially verify findings before trusting them, or turn a repetitive multi-agent task into a reusable saved script. Produces a runnable workflow script (inline or saved under .claude/workflows/<name>.js) plus its launch call. Trigger on 'author a workflow', 'make a workflow', 'new workflow', 'write a workflow', 'orchestrate agents', 'fan out subagents', 'pipeline these agents', 'workflow skill', 'turn this into a workflow'. Do NOT trigger for invoking an existing named workflow (just call the Workflow tool), for a single-agent task (use the Agent tool), or for debugging a workflow run (read its transcript dir).
Instalação
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Author a new Claude Code Workflow — a deterministic multi-agent orchestration script driven by the Workflow tool (agent / pipeline / parallel / phase / log), where the script, not the model, decides control flow. Use when the user wants to build, create, or design a workflow, fan out subagents over a work-list, pipeline multi-stage agent work, adversarially verify findings before trusting them, or turn a repetitive multi-agent task into a reusable saved script. Produces a runnable workflow script (inline or saved under .claude/workflows/<name>.js) plus its launch call. Trigger on 'author a workflow', 'make a workflow', 'new workflow', 'write a workflow', 'orchestrate agents', 'fan out subagents', 'pipeline these agents', 'workflow skill', 'turn this into a workflow'. Do NOT trigger for invoking an existing named workflow (just call the Workflow tool), for a single-agent task (use the Agent tool), or for debugging a workflow run (read its transcript dir).
workflow-author
A practice for writing a Workflow: a plain-JavaScript script that the Workflow tool runs in the background to orchestrate many subagents deterministically. The script — not the model — decides the control flow: what fans out, what runs in sequence, what verifies what, when to stop.
A workflow earns its cost by buying one of three things a single context can't: comprehensiveness (decompose and cover in parallel), confidence (independent perspectives + adversarial checks before committing), or scale (migrations, audits, sweeps too big to hold in one head). If the task buys none of those, it is not a workflow — it is an Agent call or an inline tool call. Burden of proof is on orchestration.
This skill is the authoring companion. To run an existing workflow, just call the tool. To debug a run, read its transcript dir. To build a NEW one, you are in the right place.
When a workflow — and when not
Reach for a workflow ONLY when at least one holds:
The work decomposes into ≥3 independent units that each want their own subagent.
The answer must be verified by an independent agent before you trust it (find → adversarially-verify).
The work-list is large/unknown and you want loop-until-dry or loop-until-budget coverage.
It's a repeatable pipeline worth saving as a named workflow.
Stay solo (inline tools) or use a single Agent when: the task is one read/search/edit, a quick question, or a linear job with no fan-out. One subagent is not a workflow.
Hybrid is usually right: scout inline first (list the files, find the channels, scope the diff) to discover the work-list, then call the workflow to pipeline over it. You don't need to know the shape before the task — only before the orchestration step.
Beyond one run — the multi-run campaign. A single workflow is one run that returns once. A long horizon is a chain of runs, stitched by real commands the caller executes between them — and the caller (a live session, a headless claude -p, or a bash while) has the full toolset the workflow VM lacks: filesystem, git, exec. Persistence lives in the seam, not the run. The loop the caller owns:
1. Workflow(...) returns its structured object.
2. Caller PERSISTS it — write/append STATE.md, `git commit` the checkpoint.
3. Caller GATES it with a real command — run the tests / `tsc --noEmit`;
advance only on exit 0. On failure: bump an attempt counter in STATE.md,
re-fire or HALT past a cap.
4. Caller fires the NEXT Workflow(...) with args derived from the last return.
Depth-1 workflow(name, args) composes runs inside one run; multi-run chaining happens one level up, in the caller, where the between-run commands run. The reference implementation is the mega chain — mega-brainstorm → mega-plan → mega-build → mega-ship, four separate workflow runs whose caller threads .ai/plan/<name>/ between them as the persisted state. So authoring for a long horizon = authoring the phase-workflows AND the thin caller-loop that persists + gates between them: the state file, the git checkpoint, and the exit-0 gate are the caller's job, not the workflow's. Three durability tiers, by what the state must outlive: the parent's attention → agent(); the run's crash → the workflow journal (resumeFromRunId, same-session); the machine's power / a session gap → git + STATE.md on disk, re-read by the next run cold. A reboot doesn't end the campaign — the next caller reads STATE.md and fires the next run.
The mental model
agent(prompt, opts?) — spawns ONE fresh subagent. Returns its final text (string). With opts.schema (a JSON Schema), the subagent is forced to emit validated structured output and agent() returns the parsed object — no parsing, no "extract the JSON" prompting. Returns null if the user skips it or it dies terminally — .filter(Boolean) defensively.
pipeline(items, ...stages) — each item flows through ALL stages independently, no barrier between stages. Item A can be in stage 3 while item B is still in stage 1. THE DEFAULT for multi-stage work. Wall-clock = slowest single-item chain.
parallel(thunks) — runs thunks concurrently and awaits all of them (a barrier). A throwing thunk resolves to null (the call never rejects) — .filter(Boolean). Use only when you genuinely need every result together.
phase(title) / log(msg) — progress grouping and a narrator line in /workflows.
args — the value you pass as the tool's args, verbatim. How you parameterize a named workflow.
budget — {total, spent(), remaining()}; a shared token pool across the main loop and all workflows this turn.
workflow(name, args) — run another workflow inline. One level of nesting only.
The subagent's final text is the return value — agents are told this, so they return raw data, not chatty prose. Schemas make that contract enforceable.
Quick reference:
primitive returns barrier? use for
agent(prompt, opts?) text | object — one subagent (schema → validated object)
pipeline(items, ...st) array (aligned) NO per-item multi-stage fan-out (DEFAULT)
parallel(thunks) array (aligned) YES need ALL results together
workflow(name, args) child's return — compose a sub-workflow (depth-1 only)
phase(title) / log(msg) — (sync) — progress grouping / narrator line — don't await
cap value on exceed
concurrency (at once) min(16, max(2, cores-2)) excess queues
agent lifetime / run 1000 throws WorkflowAgentCapError
items per call 4096 throws (no truncation)
token budget your +Nk target (or null) throws once spent ≥ total
Anatomy
Every script MUST begin with a meta literal — pure literal, no variables/calls/interpolation:
export const meta = {
name: 'kebab-name',
description: 'one line — shown in the permission dialog',
phases: [ // one entry per phase() call; titles matched exactly
{ title: 'Find', detail: '...' },
{ title: 'Verify', detail: '...' },
],
}
// body: use agent()/parallel()/pipeline()/phase()/log(); await directly (async context)
Then the body. Match phase() titles to meta.phases titles exactly. Inside pipeline()/parallel() stages, set opts.phase explicitly so agents land in the right progress group (don't rely on the global phase() cursor — it races).
The core decision: pipeline vs barrier
DEFAULT TO pipeline(). A barrier (await parallel(...) between stages) is correct ONLY when stage N needs cross-item context from ALL of stage N-1:
Dedup/merge across the full result set before expensive downstream work.
Early-exit on total count ("0 found → skip verification").
Stage N's prompt references "the other findings".
A barrier is NOT justified by "I need to flatten/map/filter first" (do it inside a pipeline stage), "the stages are conceptually separate", or "it's cleaner". Barrier latency is real: if the slowest item is 3× the fastest, a barrier wastes the fast items' idle time.
Smell test — if you wrote const a = await parallel(...); const b = transform(a); const c = await parallel(b.map(...)) and transform has no cross-item dependency, that middle barrier is wrong. Rewrite as a pipeline with the transform inside a stage.
The canonical shape (each dimension verifies the moment its review completes — no wasted wall-clock):
When a barrier IS right — dedup across all findings before verifying:
const all = await parallel(DIMENSIONS.map(d => () => agent(d.prompt, { schema: FINDINGS })))
const deduped = dedupe(all.filter(Boolean).flatMap(r => r.findings)) // needs ALL at once
const verified = await parallel(deduped.map(f => () => agent(verifyPrompt(f), { schema: VERDICT })))
Authoring recipe
Scope inline. Discover the work-list with cheap tool calls before orchestrating. Decide what the items are.
Write meta — name, one-line description, one phases entry per phase.
Pick the shape — pipeline (default) or barrier (only if a stage needs all prior results). Loop (until-dry / until-budget / until-count) if the work-list is unknown-size.
Define schemas for every structured stage — they replace "return JSON" prompting and auto-retry on mismatch. Mark required fields tightly.
Write prompts as functions of the item; tell each agent its output IS the return value; end with "Structured output only."
Verify what matters — an independent agent (or a 3-vote panel) per claim/finding. Default skeptics to "refuted unless proven." Independence is structural, not rhetorical: the producer and the verifier/judge/scorer are ALWAYS separate agent() calls — never one agent asked to do the work and grade it in the same breath.
Synthesize — merge dupes, rank, cap; return a structured object with a stats block for observability.
Degrade gracefully — every dead-end (!result, empty pool, all-refuted) returns a useful partial object, never throws away the run.
Quality patterns (compose freely)
Adversarial verify — N independent skeptics per finding, each prompted to REFUTE; kill on majority. Prevents plausible-but-wrong findings surviving. (deep-research uses 3 votes, 2 refutes kill.)
Perspective-diverse verify — when a finding can fail multiple ways, give each verifier a distinct lens (correctness / security / repro) instead of N identical refuters.
Judge panel — generate N independent attempts from different angles, score with parallel judges, synthesize from the winner grafting runners-up.
Loop-until-dry — keep spawning finders until K consecutive rounds surface nothing new (dedup against a seen set, NOT against confirmed — else rejected findings reappear forever). Normalize the seen-key on stable identity (file + root-cause location, lowercased), not raw titles — finders reword, and a title-keyed set lets the same issue re-enter every round.
Loop-until-budget — while (budget.total && budget.remaining() > 50_000) { ... }. Guard on budget.total or remaining() is Infinity and you hit the agent cap.
Multi-modal sweep — parallel agents each searching a different way (by-container / by-content / by-entity / by-time); each blind to the others.
Completeness critic — a final agent asking "what's missing — modality not run, claim unverified, source unread?"; its output is the next round.
No silent caps — if you bound coverage (top-N, sampling, no-retry), log() what you dropped. Silent truncation reads as "covered everything".
Chained build (advancing state) — for a workflow that advances an artifact leg by leg (not audits a static one), three controls keep a headless run honest. (1) Ground truth over the predecessor's report — each stage re-reads the actual artifact (the git diff, the file, the test output) rather than trusting the prior agent's prose that it succeeded; a producer's "done" is a claim, the next agent reads the tree. (2) Exit-0 gate, not an LLM opinion — a build leg counts as done only when a command an agent runs exits 0 (test passes, tsc --noEmit clean, file exists); machine-check code, reserve the skeptic-agent/LLM-judge for prose and findings. (3) Bounded-attempt stuck-detector — a leg that fails its gate loops to fix, but capped: N attempts, then HALT and return a blocked object (or surface an AskUserQuestion fork), never a silent re-spin. Track attempts per leg in the accumulator you spread forward, and log() the halt.
Surface progress via a message field + phases[] digest — a workflow is headless and returns once; it can't push to main chat mid-run (log() only feeds the live /workflows view). So give every agent schema a message: string ("one-line status for the human"), log() each as it lands (live view), AND accumulate them into a phases[] array in the return value (what main chat actually reads at completion). The return is the channel; build the per-phase, per-agent report into it. For reaction during the run, split into phase-workflows (decisionNode) — that's the only way to get the main loop in the loop between phases.
Verbatim vs generated text (conversation / debate / game / multi-turn workflows) — when agents feed a running transcript, split the two text-kinds at the schema. Verbatim source (a prior message, a posed riddle, the question under test) lives in the script's transcript array and is passed to the next agent as data to react to, never to reproduce. Generated contribution (the reply, the move, the guess) is all the agent should emit. Left loose, a weak agent leaks the source — parrots the prompt's clues back as "analysis," and in a hidden-answer game it states the solution in its open line, killing the suspense the judge is supposed to resolve. Guard explicitly: (1) split the hidden literal (judged, e.g. guess) from the spoken line (rendered, e.g. attempt), and in the spoken field's description forbid quoting/paraphrasing the input and stating the answer; (2) under weak models (model:'haiku') persona/voice collapses to a neutral analyst register — re-assert voice forcefully per call (a VOICE block in the prompt), don't trust the system-prompt capsule alone.
Scale to the ask: "find any bugs" → a few finders, single-vote. "thoroughly audit" / "be comprehensive" → larger pool, 3–5-vote adversarial, synthesis stage.
Hard constraints & gotchas
These are reverse-engineered from the runtime and confirmed against the binary — see references/internals.md for the decoded evidence.
Plain JavaScript, not TypeScript. No type annotations, interfaces, or generics — they fail to parse.
No Date.now() / Math.random() / argless new Date() — they THROW. They would break deterministic resume. Pass timestamps via args; for variety, vary prompts by index. Stamp wall-clock time after the workflow returns.
No filesystem / Node APIs in the script body. (Subagents spawned via agent() have full tools — push file work into them.)
Concurrency cap = min(16, max(2, cores - 2)) agents running at once, per workflow. Pass 100 items to pipeline/parallel and they all complete — only ~cap run at a time; the rest queue.
Lifetime cap = 1000 agent() calls per workflow run (a runaway backstop). Loops must terminate well under this.
Per-call item cap = 4096 items per single pipeline/parallel call — exceeding is a hard error, not a silent truncation.
Budget is a HARD ceiling and a SHARED pool — spent() counts output tokens across the main loop AND every workflow this turn. Once spent() >= total, further agent() calls throw. budget.total is null when no +Nk target was set (then remaining() is Infinity).
isolation: 'worktree' is expensive (~200–500ms + disk per agent). Use ONLY when agents mutate files in parallel and would conflict; the worktree auto-removes if unchanged. Conflict includes READERS: a verifier running tree-wide checks (tsc --noEmit, tests, git status) while sibling writers are mid-edit races a half-mutated tree — "different files" does not make it safe. Either isolate the writers in worktrees, scope verification to the single file + its own diff, or barrier all writes before any tree-wide check. And worktree edits do NOT merge back — an isolated agent's changes strand in its worktree. If the deliverable is a mutated main tree, collect each writer's diff in its return value and add an explicit integrate stage that applies the verified diffs to the main tree (serially, or via one final agent).
Nesting is one level — workflow() inside a child throws.
meta must be a pure literal — the harness reads it statically before running the body.
30s synchronous-body ceiling — the script's synchronous JS (everything between awaits) is killed at 30s with Script execution timed out after 30000ms and agent_count: 0. Agents run async outside this budget (a run can last minutes), but heavy pure-JS setup — a cartesian product, a big sort, building a huge work-list — must stay under 30s. Cap-bound any generated list as you build it, don't build-then-slice.
Stringified args fails SILENTLY, worse than throwing — if args arrives as a JSON string (not a value), args.map/args.filter throw loudly, but args.length returns the string's length (a number), args.charset is undefined (→ silent default). A numeric args.length fed into a loop/Math.pow/product builds an astronomically large list and trips the 30s ceiling as an unexplained hang. Harden every args-consuming workflow: if (typeof args==='string') args=JSON.parse(args), then validate/clamp every numeric field before using it to size anything.
Anti-patterns (how workflows fail)
The recurring ways an authored workflow goes wrong — catch these in review:
Anti-pattern Why it bites Do instead
parallel() between every stage barrier wastes fast items' idle time pipeline(); barrier only for cross-item needs
bare value returned mid-pipeline drops upstream accumulator state spread it forward: (s) => ({...s, more})
null returned to mean "condition off" silently early-drops the item (no log) return a sentinel object; branch in next stage
passing promises to parallel() TypeError "wrap each call" pass thunks: () => agent(...)
no schema on a structured stage free-text you must parse + may drift schema → validated object, auto-retry
loop on remaining() with no budget remaining()=Infinity → hits 1000-cap guard `while (budget.total && ...)` + hard count
dedup against confirmed, not seen judge-rejected items reappear forever dedup against a `seen` set
single rubber-stamp verifier plausible-but-wrong survives ≥3 skeptics, default refuted-if-uncertain
Date.now()/Math.random() in body THROWS (breaks resume) inject via args; vary prompts by index
silent top-N / sampling cap reads as "covered everything" log() what you dropped
fs/exec in the script body no fs in the VM push it into an agent() (subagents have tools)
mutating files in parallel, no wt concurrent edits collide isolation:'worktree' for parallel writers
agent restates the input it was given leaks source as analysis; spoils answers pass source as transcript data; schema: don't quote/paraphrase, answer in hidden field
trusting system-capsule voice on haiku persona flattens to neutral analyst re-assert a VOICE block per call; split hidden vs spoken fields
build-then-slice a huge gen list 30s sync-body timeout, agent_count 0 cap-bound generation as you build (stop at CAP)
stringified args sizing a loop silent hang (num .length) not a throw parse string args + clamp numeric fields first
unanchored rubric across batches same input scored at both extremes anchor edge cases in the prompt (e.g. "no meaning → score 1")
same agent generates AND judges self-graded output; scores inflate separate executor and judge agents; judge gets the output as data only
verifying shared tree mid-write tsc/tests race a half-mutated repo worktree the writers, verify per-file+diff, or barrier writes first
worktree edits assumed to land deliverable strands in orphan worktrees return diffs; integrate stage applies verified diffs to the main tree
one merge agent eats the whole pool 100s of findings overflow its context map-reduce: merge chunks (~50), then merge the merges; truncate evidence per item
mutating objects returned by journaling serializes results — you get collect into a keyed map, apply to your own
parallel()/pipeline() CLONES; mutations silently vanish objects in the same stage scope
LLM-judge verifies buildable code vibes pass a broken build exit-0 command gate (test/tsc/file-exists); LLM-judge for prose only
stage trusts predecessor's "done" builds a leg on an unverified success re-read ground truth (git diff/file/test output), not the report
fix-loop with no attempt cap silent infinite re-spin on a stuck leg cap attempts/leg → HALT + blocked object / AskUserQuestion
one run expected to span the horizon journal ≠ cold-boot; state dies on gap chain N runs; caller persists STATE.md + git-commits + exit-0-gates between Workflow() calls
Failure modes & error handling
A workflow runs headless — design for partial failure, because you won't be there to catch it. Map each failure to a response:
Failure Surfaces as Handle by
agent() user-skip or terminal error returns null .filter(Boolean) every batch before use
schema agent never produces output THROWS (not null) try/catch if a missing result is tolerable
invalid JSON Schema THROWS (async) validate the schema shape before the run
one thunk throws in parallel/pipeline that slot → null (call still resolves) null-check elements; never try/catch one slot
budget exhausted mid-run bare await agent() THROWS; do valuable work first; expect short result
inside parallel/pipeline → null slots sets; treat a short array as possible truncation
>4096 items in one call THROWS at entry, launches nothing chunk the array yourself
1000-agent lifetime cap THROWS WorkflowAgentCapError bound every loop with a hard counter
meta not a pure literal run rejected pre-launch no vars/calls/interpolation in meta
script won't parse (TS syntax, etc.) rejected at launch plain JS only; balance-check before launch
run hangs / you must change something stop, edit script, resume {scriptPath, resumeFromRunId} — prefix replays
The discipline (recipe step 8): every dead-end returns a useful partial object with a stats block — never throw away a run that did real work. A workflow that finds nothing should still report what it tried.
Iterate & resume
Every invocation persists its script under the session dir and returns the path. To iterate: edit that file and re-invoke with {scriptPath: "<path>"} instead of resending the whole script. To resume after a pause/edit: {scriptPath, resumeFromRunId: "<runId>"} — the longest unchanged prefix of agent() calls returns cached results instantly; the first edited/new call onward runs live. Same script + same args → 100% cache hit. (This is exactly why Date.now/random are banned — they'd poison the cache key.)
Saving as a named workflow
Default save location: ~/.claude/workflows/<name>.js (user-level / global) — invoke from any project via Workflow({name: '<name>', args}). Use project-level .claude/workflows/<name>.js only when the workflow is repo-specific and shouldn't leak to other projects. meta.name MUST match the filename for name-invocation to resolve. Parameterize through args — pass real JSON values (arrays/objects), never a JSON-encoded string. The two bundled workflows are the reference implementations: deep-research (visible) and code-review (registered hidden:true, launched by the /code-review skill at high+ effort).
Shipping checklist
meta is a pure literal; one phases entry per phase() call, titles matched.
Default is pipeline(); every await parallel(...) barrier has a named cross-item reason.
Every structured stage has a schema; prompts end with "Structured output only."
Results .filter(Boolean) before use (agents can return null).
What matters is independently verified (skeptic or panel), defaulting to refuted-if-uncertain — and no agent judges/scores its own output.
Parallel writers can't race verifiers or each other (worktrees, per-file verify, or barrier writes before tree-wide checks); merge/synthesize stages chunk when the pool can be large.
Every dead-end returns a useful partial object with a stats block.
Advancing/build legs gate on an exit-0 command (not an LLM opinion), re-read ground truth over the prior stage's claim, and cap fix-attempts per leg before halting.
A long horizon is authored as a chain of runs: the caller persists STATE.md, git-commits a checkpoint, and exit-0-gates between each Workflow() call — the phase-workflows plus the thin caller-loop, not one run.
No Date.now/Math.random/new Date(); no TS; no fs in the body.
Loops terminate (until-dry counter / budget guard / hard count) well under 1000 agents.
Coverage caps are log()-ged, not silent.
References
references/workflow-tool-spec.md — the verbatim Workflow tool specification (source of truth; version-locked to the installed binary).
references/internals.md — reverse-engineered runtime: how pipeline/parallel/agent, the scheduler, journaling/resume, and budget actually work, with decoded code evidence.