Skip to content

docs(rules): add workflow-vs-skill.md and the bundled-workflow layout convention #2163

Description

@laurigates

Groundwork for the dynamic-workflow migration. Blocks every harness issue — nothing should ship a .js before this convention exists.

Source: docs/plans/dynamic-workflow-migration.md §Repo-level consequences, items 1–3 (merged in #2162).

Why

The migration establishes a third authoring substrate — prose skill / shell script / workflow .js. The repo has rules for the first two only. Without a written gate, the next author reaches for a harness on any skill that merely looks parallel.

1. .claude/rules/workflow-vs-skill.md

Scope it with paths: per .claude/rules/context-engineering.md so it is not always-loaded:

paths: ["*/skills/**/workflows/*.js", "*/skills/**/SKILL.md"]

Content:

  • The three gating axes. Is N enumerable by something other than the model? Is the barrier load-bearing? Is the loop bound script-decidable?
  • The separating criterion, which is the plan's central finding: the fan-out width must already be enumerable by something other than the model. Every mover reads its N from a source that already exists (list-components.sh's COMPONENT= rows, a candidate manifest, len(evals) × runs × configs); every rejection either invented its N or duplicated a bound a script already enforces.
  • The cost rule that killed 6 of 18 candidates: if the fan-out width or the classification is already computed by a check-*.sh, a workflow that re-derives it in agents is offload-to-deterministic-substrate.md run backwards.
  • The two shapes with no fit here, and why — tournament (this repo's ranking signals are deterministic scores from grade_deterministic.py, not judgements) and loop-until-done (every loop here is bounded by an enumerable set before it starts; the one true loop, workflow-checkpoint-refactor, needs state across session boundaries and a workflow script runs inside one invocation).
  • The context: fork corollary: if a skill already holds fork, "the output floods the main window" is not available as a justification. That argument is already spent for 8 skills.

Position it as a sibling of loop-integrity.md and structured-script-output.md, directly under offload-to-deterministic-substrate.md.

2. CLAUDE.md

  • One row in the Rules table for the new rule.
  • One line in Project Structure adding workflows/ to the plugin layout: skills/<skill-name>/workflows/*.js.

Nothing else — the file is hand-curated and this is a directory-layout fact, not a new lifecycle.

3. .claude/rules/plugin-structure.md

  • Location convention: bundled beside SKILL.md, named <purpose>.workflow.js.
  • A bundled workflow must be reachable from a ## Workflow harness (template) section in its sibling SKILL.md. An orphan .js is dead weight.

4. The reusable framing snippet

The blog post's guidance is that a skill-bundled workflow be framed as a template to adapt, not a script to run verbatim. Land this snippet in the rule so every harness issue can copy it verbatim — slot 3 is what makes it a template, because naming what an adapter may rewrite implies everything else is structure:

## Workflow harness (template)

`workflows/<name>.workflow.js` ships beside this skill. **It is a TEMPLATE to adapt,
not a script to run verbatim.** Read it, then rewrite it for the work in front of you.

**Adapt freely:** [the agent prompts, the partition/fan-out width, the filter rules,
the project-specific commands].

**Preserve across any adaptation:** [(a) the loop bound comes from <the deterministic
source>, never from a prose "for each"; (b) <the schema/enum that forces a determinate
verdict>; (c) <the barrier and why it is a barrier>].

**Skip the harness when:** [<the modal small case>] — that is a linear pass and the
harness is pure overhead. The steps below remain the authoritative description of
*what* each stage must produce; the harness only fixes *how* the work is split.

Plus two clauses every template dispatching isolation:'worktree' agents must carry:

Never Workflow({resumeFromRunId}) to retry a few failed worktree agents — a resume re-runs agents that already succeeded and opens duplicate PRs (#1868). Re-dispatch the failed units fresh and sequentially after checking gh pr list --head <branch> --state all --json number,state.

Push, PR creation, and GitHub mutations happen only in the single sequential finalise stage, never inside a fanned-out agent.

Explicitly out of scope

No new skill in workflow-orchestration-plugin. The convention is about a page and belongs in the paths:-scoped rule — a skill would cost listing tokens in every session for content read once per authoring act.

Acceptance

  • .claude/rules/workflow-vs-skill.md exists, paths:-scoped, covering all five content bullets
  • CLAUDE.md rules-table row + Project Structure line
  • plugin-structure.md location + reachability convention
  • The framing snippet is copy-pasteable from the rule

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions