Skip to main content

create-workflow

Author a new agent-almanac workflow — a self-contained `.mjs` orchestration script run by Claude Code's Workflow tool. Covers choosing a workflow over a team, copying the template, the triple-name discovery contract, the pure-literal meta and sidecar frontmatter, building the body with the injected primitives, the advisory/implementing capability contract, the adversarial-verification fail-safes, validation, and manual installation. Use when you have a repeatable, parameterized procedure that coordinates several agents and want it captured as a reusable, auditable artifact whose control flow is fixed in code.

Aller à l'installation

Informations de source

Dépôt
pjt222/agent-almanac
Dernière activité de la source
17 septembre 2026 à 13:52
Langue détectée de SKILL.md
anglais
Étoiles
34
Forks
4

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
create-workflow
description
Author a new agent-almanac workflow — a self-contained `.mjs` orchestration script run by Claude Code's Workflow tool. Covers choosing a workflow over a team, copying the template, the triple-name discovery contract, the pure-literal meta and sidecar frontmatter, building the body with the injected primitives, the advisory/implementing capability contract, the adversarial-verification fail-safes, validation, and manual installation. Use when you have a repeatable, parameterized procedure that coordinates several agents and want it captured as a reusable, auditable artifact whose control flow is fixed in code.
license
MIT
allowed-tools
Read Write Edit Bash Grep Glob
metadata
{"author":"Philipp Thoss","version":"1.1","domain":"general","complexity":"intermediate","language":"multi","tags":"meta, workflow, creation, orchestration","locale":"ja","source_locale":"en","source_commit":"ef9445268","fence_basis_commit":"ef9445268","translator":"(untranslated stub)","translation_date":"2026-06-16"}
# Create a New Workflow Author a workflow — the fifth content type — as a self-contained `workflows/<name>.mjs` script run by Claude Code's Workflow tool. A workflow fixes its phases, fan-out, and verification structure in JavaScript: its **control flow** is deterministic and rereadable, while the **outputs** of its `agent()` calls are LLM subagents and remain nondeterministic. This skill is the *procedure* for authoring one; [`guides/creating-workflows.md`](../../guides/creating-workflows.md) is the API *reference* it draws on. > **Vendor-API caveat.** The Workflow run model is generally available on paid Claude Code plans (~v2.1.154+), but the script-authoring surface (the injected `agent()` / `parallel()` / `pipeline()` / `phase()` / `log()` / `workflow()` primitives and the `args` / `budget` globals) is an evolving vendor API — accurate as observed in Claude Code v2.1.x, subject to change, never CI-enforced. ## When to Use - You have a repeatable, parameterized procedure that coordinates several agents and want it captured as a reusable artifact whose shape you already know. - You need a review, research, or migration procedure to run the same way every time, with the fan-out and verification logic auditable in code rather than re-decided by a lead each run. - You are adding a reviewed seed to the `workflows/` library, or authoring a personal workflow for `.claude/workflows/`. - You are deciding between writing a [team](../create-team/SKILL.md) and a workflow — read Step 1 first. ## Inputs - **Required**: Workflow name (lowercase kebab-case, e.g., `review-changes`). This becomes the filename stem, the sidecar `name:`, and `meta.name` — all three must be identical. - **Required**: Purpose (one paragraph: what repeatable procedure this codifies and why its control flow should be fixed in code). - **Required**: Phase plan (the named stages, e.g., Classify → Verify → Synthesize) and the fan-out shape (per-item `pipeline()` vs barrier `parallel()`). - **Optional**: Parameters the workflow accepts via `args` (default them so it runs with no input). - **Optional**: Source material (an existing ad-hoc multi-agent procedure to formalize). ## Procedure ### Step 1: Confirm a Workflow Is the Right Tool A workflow is one of five content types. Choose deliberately: - A **skill** is how *one* agent performs a procedure. A **team** is a declarative roster the lead coordinates at runtime (model-driven, adaptive). A **workflow** is a script whose phases and fan-out are fixed in code (deterministic control flow, auditable, parameterized). - Pick a **workflow** only when the coordination shape is known in advance and you want it repeatable and rereadable. If the right next step depends on what the last step found, pick a **team** instead. **Expected:** A one-line justification for why this is a workflow and not a team or a single skill. **On failure:** If the coordination must adapt turn-by-turn, stop and use `create-team`. If only one agent acts, use `create-skill`. ### Step 2: Copy the Template Start from the canonical scaffold — never a blank file: ```bash cp workflows/_template.mjs workflows/<name>.mjs ``` For a personal (non-library) workflow, copy into `.claude/workflows/<name>.mjs` instead. The template carries the sidecar block, a pure-literal `meta`, a `phase()`, a `pipeline()` fan-out, an `agent({ schema })` call, and the hard constraints inline. **Expected:** A new `.mjs` file that is a verbatim copy of the template. **On failure:** If `workflows/_template.mjs` is missing, you are on a pre-Phase-1 checkout — fetch `main`. ### Step 3: Satisfy the Triple-Name Discovery Contract Rename in the three places that **must stay identical** — the filename stem, the sidecar `// name:`, and the `meta.name` literal: ```bash grep -n "name:" workflows/<name>.mjs # sidecar + meta.name must equal the filename stem ``` That triple equality (`filename ↔ sidecar name ↔ meta.name`) is the `Workflow({ name })` and `/<name>` discovery contract. **Expected:** All three read the same kebab-case name. **On failure:** A `Workflow not found by name` error at runtime means the triple is out of sync — re-check all three. ### Step 4: Write the Pure-Literal `meta` and Sidecar `export const meta` must be a **pure literal** — no variables, function calls, spreads, or template interpolation. Required fields: `name` and `description`. `phases` (one entry per phase the workflow uses, whether opened by a global `phase()` call or a stage's per-call `phase:` option) is optional but recommended. Mirror `name`, `description`, and the `phases` titles in the top-of-file sidecar comment block — the sidecar is the **catalog source of truth** (the analogue of YAML frontmatter on the other content types), readable by grep without a JS parser. **Expected:** `meta` is a literal object; the sidecar agrees with it; `phases` ⊇ every title passed to `phase()` or a stage `phase:`. **On failure:** A `meta must be a pure literal` error means a value references a variable or call — inline it. ### Step 5: Build the Body The body runs inside an async wrapper — use top-level `await` and a top-level `return` directly. Compose with the injected globals (no imports): - `pipeline(items, ...stages)` — the **default**: each item flows through every stage with no barrier between stages (wall-clock = slowest single chain). - `parallel(thunks)` — a **barrier**: use only when a stage needs every prior result at once (dedup, an early-exit count, a synthesis step). - `agent(prompt, { schema, label, phase, agentType })` — spawn one subagent; with `{ schema }` it returns a validated object. - `phase(title)`, `log(message)`, and the `args` / `budget` globals. Default `args` so the workflow runs with no input. Pass a JSON Schema as `{ schema }` to force structured output (no free-text parsing). See `guides/creating-workflows.md` for the full primitive reference. **Decide the durability model before writing the body.** The script cannot touch the filesystem, so it cannot checkpoint itself: an interrupted `Workflow(...)` call returns nothing whichever fan-out primitive it used, and `resumeFromRunId` is **same-session only** (the tool's own contract; observed here for process death) — once the launching session is gone, so is the run. Answer in one line: *what survives if this run dies halfway?* The invariant is that every expensive result is on disk before the run can die; the two ways to get there differ in where that write happens and compose freely. Either the agents write validator-gated artifacts to disk as they go (the [`batch-generate-waves`](../../workflows/batch-generate-waves.mjs) model — a stage that dies then loses only its unfinished items), or the invoker splits the run into batches and persists each batch's results between `Workflow(...)` calls, or both. Salvaging a run that did neither means hand-parsing `~/.claude/projects/<project-slug>/<session-id>/subagents/workflows/<runId>/journal.jsonl`, which recovers the results that finished, not the run. Full treatment: [`guides/creating-workflows.md`](../../guides/creating-workflows.md) § Surviving an Interrupted Run. **Expected:** A body that defaults its inputs, fans out with the right primitive, returns a value, and a one-line answer to what survives if the run dies halfway. **On failure:** If you reach for `parallel()` only to flatten or map between stages, that barrier is not justified — do the transform inside a `pipeline()` stage. If the honest answer to the durability question is "nothing", changing the primitive will not help: move the writing into the agents, or split the run into batches the invoker persists between. ### Step 6: Honor the Capability Contract (#285) `agent({ agentType })` names the spawn type per call — the workflow's native expression of the persona-vs-spawn decoupling. The `intent` rule applies: - A stage that **mutates artifacts** (uses Write/Edit/Bash to change files, or runs under `isolation: 'worktree'`) must target an **implementing** agent type. - A **read-only analysis** stage targets an **advisory** type (e.g., `Explore`). Set `agentType` explicitly on every stage so the contract is visible, not implied. **Expected:** Every `agent()` call names an `agentType` whose capability matches what the stage does. **On failure:** A mutating stage targeting an advisory type cannot write — switch it to an implementing type such as `general-purpose`. ### Step 7: Apply the Adversarial-Verification Fail-Safes If your workflow verifies candidate findings (the classify → refute → synthesize spine), bake in the three lessons the `review-changes` seed encodes: 1. **Gate on affirmative confirmations, not refutations.** `agent()` returns `null` when a subagent is skipped or dies, so `filter(Boolean)` before counting and require a *majority of confirmations* to survive (`confirmedVotes >= Math.floor(n / 2) + 1`). Surviving when "few enough refuted" inverts the fail-safe — a dead refuter would let an unverified finding through. 2. **Give verifiers the evidence the proposer had.** If the classifier read a diff, tell the refuters to read it too — otherwise change-specific findings get default-refuted and unfairly killed. 3. **Default to refuted/unconfirmed** unless a verifier can independently reproduce the finding. **Expected:** Survival gates on a confirmation quorum, verifiers share the proposer's evidence, and `null` results are filtered. **On failure:** If real findings vanish, check that verifiers aren't starved of context (lesson 2); if junk survives, check the gate counts confirmations, not refutations (lesson 1). ### Step 8: Validate the Script Workflow scripts use a top-level `return`, which the runtime accepts (it wraps the body in an async function) but raw ESM rejects — so plain `node --check` reports `Illegal return statement` on a valid workflow. Use the wrap-then-check recipe: ```bash { echo '(async()=>{'; \ sed 's/^[[:space:]]*export const meta/const meta/' workflows/<name>.mjs; \ echo '})()'; } | node --check - ``` The authoritative check is running it: `Workflow({ name: '<name>' })`. **Expected:** The wrap-check passes with no syntax error. **On failure:** Do **not** "fix" a top-level `return` to pass raw `node --check` — that would cripple the script. Use the wrap-check; debug any other syntax error normally. ### Step 9: Install and Run The Workflow tool resolves `Workflow({ name })` from `.claude/workflows/<name>.mjs`. In Phase 1, install by hand: ```bash cp workflows/<name>.mjs .claude/workflows/<name>.mjs # curated installs prefix: almanac-<name>.mjs ``` Then invoke `Workflow({ name: '<name>' })` or the `/<name>` slash command. `.claude/workflows/` is user-writable and the save-flow writes there, so a *curated* install must namespace (`almanac-<name>.mjs`) to avoid shadowing a user's own workflow. **Expected:** The workflow runs end-to-end and returns its value. **On failure:** If `/<name>` is not found, confirm the file is in `.claude/workflows/` and the triple-name contract holds (Step 3). ### Step 10: Register (Library Contributions) > **Phase-2-pending.** A `workflows/_registry.yml`, CI validation of the sidecar, and a CLI install adapter are deferred behind the #288 promotion gate (~8–10 workflows + a real install request). Until they land, a library workflow needs **no** registry entry — the sidecar frontmatter is its catalog metadata and discovery is by filename. When the registry exists, this step becomes "add an entry derived from the sidecar." > > **Workflows are excluded from i18n.** Unlike skills/agents/teams/guides, a workflow is executable code, not prose — do **not** scaffold translations for it. If contributing a reviewed seed to agent-almanac, place it in `workflows/`, cross-reference it from `guides/creating-workflows.md`, and carry the vendor-API caveat in any prose you add. **Expected:** A library workflow lives in `workflows/` with an accurate sidecar; no registry or translation steps are attempted in Phase 1. **On failure:** If a tool expects `workflows/_registry.yml`, you are ahead of the promotion gate — stop and confirm Phase 2 has shipped. ### Step 11: Contain a Fan-Out That Runs Against a Live Repository The advisory/implementing contract in Step 7 governs the agent type a stage *declares*. It does not constrain what a `Bash`-capable agent does to the working tree, and a "read-only" review fleet is exactly where that gap bites: every agent inherits the repository as its default working directory. **Name a write location in every prompt** — one sentence per `Bash`-capable stage, and the only control that reaches a stage nobody classified as writing. Name an absolute path and rule out the repository root (`Write every file you produce under /abs/path; write nothing under the repository root`), including in the read-only-by-intent stages: those are exactly the ones that pollute the repository by inherited working directory alone, with no collision, no `git add` and no intent to touch it. This is not the preamble's `mktemp -d` restated — that gives a shell block a private directory, while this covers every file the agent produces by any tool, and rules out the repository root. **Bracket the run with `repo-guard`** — this is the mechanical control. A workflow body cannot run shell (no filesystem or Node API), so this is the *invoker's* job, around the `Workflow(...)` call: ```bash npm run guard:snapshot # before launching the workflow npm run guard:verify # after it returns npm run guard:release # when the run is genuinely over ``` `verify` keeps the snapshot and `snapshot` refuses to overwrite one, so skipping `guard:release` leaves the next run failing with "a snapshot already exists". That is deliberate — re-arming mid-run would rebaseline the damage — but it means release is part of the loop, not an optional tidy-up. Note also that npm swallows `--release` as its own config, which is why there is a script rather than a flag. It compares HEAD, branch, worktree status, the content of every changed or untracked file, and index flags. Exit 1 prints the difference; exit 2 means it could not answer and must never be read as a pass. Two comparisons carry most of the weight: HEAD, the only one that catches a subagent that *committed* (the tree reads clean afterwards), and file content, without which a stray write to an already-modified file is invisible — its status line does not move. It does **not** cover ignored paths; walking them would mean hashing `node_modules`. **Contain the agents themselves.** Prepend the `REPO_SAFETY` preamble from `workflows/_template.mjs` to the prompt of every agent that may run shell commands — verifiers included, since a verifier reproducing a finding is the agent most likely to build a fixture. Copying the template gets this by default. Its rules, in the template's own order — deliberately uncounted, because a count here is a claim about a file this one does not own, and it had silently drifted by one before anyone noticed: 1. **`mktemp -d`, never a shared fixed path.** Parallel agents told to build fixtures independently converge on the same obvious filename, and the second clobbers the first. 2. **`cd "${DIR:?}" || exit 1`.** A bare `cd` that fails does not reliably abort the surrounding script, and every following relative path then resolves against the repository. Braced because `cd ""` returns 0 without moving, so an unset `DIR` leaves the agent where it started and `|| exit 1` never fires. 3. **An absolute path under `$DIR` in every destructive command, braced** — write `rm -rf "${DIR:?}/fixtures"`, never `rm -rf fixtures` and never a bare `"$DIR/fixtures"`. The `cd` above is one control; a relative `rm` makes it the only one, so the single failure it guards against becomes repository damage instead of a wasted command. The brace is not decoration: an absolute path trades the dependency on the working directory for one on `$DIR` being set, and `cd ""` succeeds without moving, so an unset `DIR` leaves the agent standing in the repository *and* expands `"$DIR/fixtures"` to `/fixtures`. `:?` refuses both, unset and empty alike, on bash 5.2 and zsh 5.9. 4. **A cwd assertion before `git add`, `git commit`, or a tool run with a write flag** — that is its scope, and it is narrower than "anything destructive", which is why rule 3 exists: an `rm` falls outside it. Braced for rule 3's reason too, since outside any repository `git rev-parse` prints nothing and an unset `DIR` makes the unbraced form compare `""` to `""` and pass: ```bash [ "$(git rev-parse --show-toplevel)" = "${DIR:?}" ] || exit 1 ``` 5. **Never `git commit`, `git update-index` or `git checkout --` against the repository itself**, and never a repo tool with a write flag there. Prefer `isolation: 'worktree'` for any stage that might mutate — it is the structural control and stronger than either of the others. The gap it leaves is the one the prompt sentence covers: a stage that is read-only *by intent* is never classified as mutating, and that is exactly the stage that pollutes by inherited working directory. So the three are complements. The prompt *prevents* a compliant agent from writing where it stands; worktree isolation *contains* a stage you expected to write; the guard *detects* what neither caught, and because a workflow body cannot run shell it runs only before and after the whole `Workflow(...)` call, blind for the duration of the fan-out. What a prompt cannot do is bind: in #493 it named the directory, the tool and the file to copy, the agent complied with all three, and the write still landed in the repository because the failure was mechanical. Instruction is worth its one sentence; enforcement is the guard's job and the worktree's. **Expected:** `npm run guard:verify` exits 0 after the run. **On failure:** Exit 1 prints what moved and the recovery command. A stray commit is recoverable while unpushed: confirm it is unpushed, state what the reset destroys, then `git reset --mixed <recorded-head>` and remove the stray files. Exit 2 means the guard could not compare — re-snapshot and re-run rather than treating it as a pass. ## Validation - [ ] File exists at `workflows/<name>.mjs` (or `.claude/workflows/<name>.mjs` for personal use). - [ ] Filename stem, sidecar `name:`, and `meta.name` are identical (triple-name contract).
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub