name: workflow-guide
description: Create, modify, review, or validate pi-workflow workflow definitions. Use when the user asks to build/customize a /workflow workflow, validate a workflow spec, choose stage topology for a workflow being authored, adapt an existing workflow definition, or explain pi-workflow authoring rules.
Use this skill before creating, editing, or reviewing a `pi-workflow` workflow.
Read the public usage guide and bundled workflow notes before giving workflow-authoring advice:
- `../../docs/usage.md`
- `../../workflows/README.md`
Resolve paths relative to this skill directory. Treat those docs as the source of truth for command surface, workflow resolution, artifact-graph semantics, safety policy, and validation.
Then read at least one shipped bundled spec as a quality reference before authoring, not only the scaffolds. The scaffolds show correct JSON shape; the bundled specs show correct *quality* — prompt discipline, evidence gates, partial-failure handling, and control/analysis split proven on real runs. Prefer the closest match:
- `../../workflows/deep-research/spec.json` — plan -> foreach research -> normalize/verify/audit -> synthesis; strong evidence and verification discipline, expensive/cheap stage separation.
- `../../workflows/deep-review/spec.json` — triage -> foreach reviewers -> support dedup -> foreach devil's-advocate -> support partition -> report; multi-pass challenge and deterministic verdict joins.
- `../../workflows/spec-review/spec.json` and `../../workflows/impact-review/spec.json` — mapping/synthesis shapes.
Copy their proven conventions (see "Quality design patterns"), not just their structure.
- Prefer a bundled workflow before inventing a new topology.
- When authoring a new workflow and a scaffold topology fits, start from `./scaffolds/<name>/` rather than inventing the JSON shape from scratch.
- Public `schemaVersion: 1` workflow specs use `artifactGraph.stages`.
- Stage order controls scheduling only; it does **not** pass prior output into a later plain `single` stage.
- If a model stage needs prior artifacts, use `single.from` or `reduce.from`; use `foreach.from` for array fan-out and support `from` for deterministic helpers. `after` is order-only.
- For static data-driven fan-out, use `foreach.from` with a simple dot path into upstream `control.json`.
- Use `each.itemIdentityPath` only for non-streaming foreach items with a stable string identity, and `each.itemPayloadPath` only for a distinct object payload. The runtime rejects missing, duplicate, unsafe, or colliding identities rather than falling back silently.
- Use `inputPolicy.terminalBarrier: "all-sources"` for an intentional all-terminal fan-in, `invalidateOnDependencyResume: true` only for static graph consumers that must discard stale generated evidence on source resume, and `maxCompiledPromptChars` when the final prompt needs a hard code-point ceiling. All three are opt-in; unsupported replay ownership fails closed.
- Use `type: "dynamic"` only for trusted adaptive orchestration that must create official child tasks at runtime with `ctx.agent()`, `ctx.helper()`, or `ctx.workflow()`. `maxNestedWorkflowDepth` is actual ancestor-relative nonconsumable headroom: depth 1 allows sibling children, not grandchildren; child settings cannot widen ancestor allowances. Missing/ambiguous ancestry grants no new depth. Keep the other work/runtime/tool budgets; depth is not a sibling-work cap. Hot `counters.nestedWorkflowDepth` is only a local 0/1 launch projection. Full retained historical depth requires explicit `readOrRebuildDynamicState(cwd, runId, { observeDescendants: true })` runtime inspection, is not persisted into the hot cache, and is never launch authority. Do not import private runtime modules into reusable helpers.
- For synthesis/fan-in, use `reduce.from` and require/encourage `workflow_artifact` reads for detailed upstream artifacts.
- For deterministic local post-processing, declare a `support` object with `support.uses` pointing to a bundle-local `./*.mjs` helper; support is trusted local code, not sandboxed subagent work and does not use a separate `type` value.
- Put already-known, caller-authorized inventory, canonical task binding, IDs, schemas, joins, counts, escaping, and rendering in static code instead of asking a model to restate or transform them. Keep models for requirements, topology, unknown discovery, domain semantics, and substantive judgment. Never substitute a fixed inventory when the workflow must discover the inventory.
- For iteration, use `loop` with fixed child stages, `maxRounds`, and deterministic `until`. A positive `maxRounds` bounds rounds; explicit `maxRounds: null` removes the round cap. For unlimited loops, omit `progressPath` to terminate only by `until`, blocking failure, or explicit stop; an explicit `progressPath` opts into no-progress stopping. Model-task time limits are separate (`maxRuntimeMs: 0` disables them). Loop children are `single`/`reduce` only, run serially, and must not declare `from`/`after`: each child implicitly sources the earlier children of its round (for example `<loop>.r01.compare`), and the first child of every later round sources the previous round plus a `# Loop Carry-Forward Context` block. `until` must target the final child (`{ "stage": "<final-child>", "path": "$.field", "equals": true }`, or `all`/`any` combinators; predicates `equals`, `notEquals`, `lengthEquals`, `exists`), and that path must exist in the final child's control schema and few-shot example. Loops cannot be resumed; start a fresh run after changing the spec. See "Loop behavior" in `docs/usage.md` for the exact contract.
- Agent-declared tools are the authority ceiling; workflow `tools` can only narrow them.
- To reuse agent knowledge across stages, declare top-level `roles` (`fromAgent` extracts safe agent sections; `prompt` appends literal text). Compiled role text is injec