build/skills/plan/SKILL.md
Use when prior artifacts are approved and the QRSPI pipeline needs detailed task specs — breaks structure into ordered tasks with test expectations, dependencies, and LOC estimates (full pipeline requires design+structure; quick fix requires only goals+research)
npx skillsauth add dfrysinger/qrspi-plus planInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
PRECONDITION: Invoke qrspi:using-qrspi skill to ensure global pipeline rules are in context. (Idempotent on session re-entry. Subagents are exempt — SUBAGENT-STOP in using-qrspi handles that.)
Announce at start: "I'm using the QRSPI Plan skill to create detailed task specs."
Break the structure into ordered, self-contained tasks following vertical slices and phases from the design. Each task spec includes exact file paths, descriptions, test expectations, dependencies, and LOC estimates. For large plans (6+ tasks), individual task specs are farmed out to sub-subagents.
This section is the single source of truth for plan.md scope boundaries. It is the locked rule set the scope-reviewer dispatch loads at review time (Read by the qrspi-plan-scope-reviewer agent at runtime per its rules-loading procedure). Boundary-drift findings, scope-compliance findings, and lexical-leakage checks all run against the enumerated items here.
Length target. plan.md aggregate length sits in the 1000–2000 lines soft window once all task specs are appended for review (the Keeplii corpus averages ~52 lines per task spec; a 10-20-task phase lands inside this band). Per-task specs are intentionally short — terse bullets, no narrative preamble, no design rationale repetition. The aggregate band is a soft target, not a ceiling: reviewers should flag a plan that drifts well outside it (e.g., 200 lines for 10 tasks signals under-specification; 4000 lines signals task specs that have grown into design or implementation prose).
INVEST Negotiable framing. A plan task spec is a conversation, not a contract. Plan owns the scoping decisions and the test expectations; downstream skills (Structure, Implement, Implement-TDD) own the implementation choices that flow from those decisions. The DEFERS list below is the operational form of "Negotiable": the items deferred to later artifacts MUST stay out of plan.md — encoding a function signature or a line-by-line algorithm in a task spec turns the spec into a contract, forecloses Structure/Implement's negotiation room, and is grounds for a scope finding from the scope-reviewer.
The plan.md artifact is the only authoring location for these concerns. Every paragraph or bulleted item in plan.md must trace to one of these:
expect(...) strings.Task 3 depends on Task 1, Task 2 or Dependencies: none). Forward dependencies are forbidden.~N per task; the policy ceiling is 200 LOC and the target is ~100 LOC; see Task Sizing for the splitting protocol.The following concerns are explicitly out of plan.md scope. Each DEFERS entry names the destination artifact that owns the concern. A finding that observes any of these in plan.md is a boundary-drift finding (change_type: scope); per the INVEST Negotiable framing above, the spec's job is to set the conversation, not pre-empt the downstream skill's negotiation.
structure.md (interface contracts per file are Structure's OWNS, not Plan's). Conversation, not contract: Plan says "rate limiter middleware exposes a single Express handler"; Structure says rateLimiter(req, res, next).expect(...) / test code → Implement-TDD (Implement's TDD cycle authors the failing test first). Conversation, not contract: Plan says "returns 429 when client exceeds 100 requests/minute"; Implement-TDD writes expect(res.statusCode).toBe(429).INCR vs. EVAL with a Lua script.design.md (locked upstream; Plan consumes, does not re-author).phasing.md / Phasing skill. Plan consumes phase boundaries from Phasing; it does not re-decide them.The following lexical patterns in plan.md indicate boundary drift from a later pipeline stage and trigger a boundary-drift finding from the scope-reviewer:
expect(, assert., assertEqual, toBe( in a Test Expectations bullet — Implement-TDD-layer leak.if/else, for, while, line-numbered logic walkthroughs — Implement-layer leak.Read config.md to determine pipeline mode. If config.md doesn't exist or has no route field, refuse to proceed and tell the user to re-run Goals to set the pipeline mode. The route field is authoritative; pipeline is informational (see using-qrspi Config File section).
Full pipeline (pipeline: full) — required inputs:
goals.md with status: approvedresearch/summary.md with status: approveddesign.md with status: approvedstructure.md with status: approvedphasing.md with status: approved (phase definitions and slice ownership)Quick fix (pipeline: quick) — required inputs:
goals.md with status: approvedresearch/summary.md with status: approvedNote: Design and Structure are not in the quick fix route, so design.md and structure.md don't exist.
If any required artifact is missing or not approved, refuse to run and tell the user which artifact is needed.
Read config.md from the artifact directory to determine whether Codex reviews are enabled.
Apply the Config Validation Procedure in using-qrspi/SKILL.md. Plan validates pipeline, route, codex_reviews, and (when pipeline: quick) question_budget.
Subagent produces plan.md overview. For large plans (6+ tasks), individual task specs are farmed out to sub-subagents (one per task or related group) to keep context manageable. Iterative with human feedback.
plan.md contains ONLY current-phase tasks. Each task must reference goal IDs that exist in goals.md. Tasks for goals not in the current phase must not appear. The goal_ids field in task frontmatter (a list, e.g. [G1, G2] — see ID-Hygiene Contract below) must contain only IDs of goals in goals.md.
Each task implements exactly one observable behavior — one request handler, one use case, one user-visible change. The task title names exactly one feature, with no + joining feature names and no two distinct verbs joined by and.
LOC budget per task:
sizing_exception (post-split frontmatter) or Sizing exception bullet (in-plan) names one of: schema migration, CI scaffolding, reusable primitives"LOC" = implementation source only (counted across files in Target files: excluding tests/). Test code has no ceiling but should be roughly proportional to behaviors covered (rule of thumb: 1.5–2× impl LOC for full-behavior coverage). A task with 100 src LOC and 250 test LOC is fine; one with 250 src LOC needs a sizing_exception or split.
Why: SWE-Bench Pro reports a median patch size of 107 LOC / 4.1 files, with frontier-model success around 23% at that size (GPT-5, Opus 4.1). OpenAI's AGENTS.md guidance targets ~100 lines per agentic task. Our 100-LOC target matches that guidance; the 200-LOC ceiling sits at the lower bound of Cisco/SmartBear's code-review sweet spot (200-400 LOC) and gives margin for QRSPI's enhanced scaffolding (fresh-context subagents, structured task specs, TDD cycle, multi-reviewer loop). Multi-feature task titles like auth + allowlist + rename + admin are the visible symptom of oversized tasks; the underlying cause is bundling N request handlers into one task, which re-couples slices that vertical-slice decomposition exists to separate.
Splitting protocol. A task estimated >200 LOC splits into N tasks at or below the ~100-LOC target, each implementing one handler with explicit dependency ordering. The closed exception set is: schema migration, CI scaffolding, reusable primitives. Mark sizing_exception: <reason> in the task frontmatter (post-split) or the Sizing exception bullet inside the in-plan task spec (pre-split), and explain in the Description.
Floor — a task is too small if any of these hold:
A task that fails any floor check merges into the parent task that gives it observable behavior; do not ship sub-atomic tasks.
A schema-migration task applies an identical mechanical change to N files of the same shape — for example, deleting one frontmatter key from every agent file, replacing a single identifier uniformly across all skill prose, or renaming a top-level YAML field across a glob of config files. This task shape recurs in this codebase and is the narrow exception to the ordinary LOC ceiling and file-count guidance.
Use sizing_exception: schema-migration only when ALL of the following hold:
Target files: receives the same structural change (same pattern, same before/after; not "similar" or "related").Do not use this exception for multi-feature bundles that happen to touch many files, for behavioral changes dressed up as migrations, or for any task where per-file human judgment is needed. The closed exception set remains: schema migration, CI scaffolding, reusable primitives — no new category is added by this contract.
When sizing_exception: schema-migration is declared, the task spec MUST carry all three of the following fields. No field is optional when the exception is used; omitting any one is a plan-spec defect:
sizing_exception: schema-migration — declares the exception; must be exactly this value for schema-migration tasks.sizing_rationale: <human-readable reason> — one sentence explaining why this specific change is a mechanical same-shape migration (e.g., "removes the deprecated model: key added uniformly by T40 from all 41 agent frontmatter files").structural_lint: <script-path> — a repo-relative path to a checked-in script under scripts/structural-lints/ (e.g., scripts/structural-lints/check-model-key-removal.sh). The value must be a single token matching the ERE ^scripts/structural-lints/[A-Za-z0-9_.-]+\.sh$; whitespace, tab, newline, and any character outside that token class are rejected. The script must exist as a regular readable file at that path in the repository; a path that passes the token check but is absent from the repository is a plan-spec defect. The script receives no spec-controlled arguments; it is invoked as bash -- <path> from the repository root with the path passed as a single argv element (never interpolated into a bash -c string) against the proposed diff. The script must exit 0 when the diff is mechanical-only and non-empty, and exit non-zero when non-structural content is present or the diff is empty. Inline bash commands are not accepted as the field value; a literal command string instead of a valid script path is a plan-spec defect.When the mandatory trio is present and the structural_lint check executes successfully on the proposed diff:
Ordinary task-size discipline is not relaxed for non-schema-migration work. A task without the full mandatory trio is evaluated against the standard ceiling.
A schema-migration declaration is incomplete — and the LOC/file-count exemption is NOT granted — when ANY of the following holds:
sizing_exception: schema-migration is declared but sizing_rationale: is absent or empty.sizing_exception: schema-migration is declared but structural_lint: is absent or empty.structural_lint: is present but its value does not match the ERE ^scripts/structural-lints/[A-Za-z0-9_.-]+\.sh$ (is an inline command, contains whitespace/tab/newline, contains .., is an absolute path, or uses characters outside the allowed token class).structural_lint: carries a token-valid path but the named script does not exist as a regular readable file at the repository root; a missing or unreadable script is a configuration defect, not a content defect, and the exemption is denied.structural_lint: names a valid, readable script path but the proposed diff is empty — a vacuous pass on an empty diff does not prove mechanical-only nature; the exemption is denied.structural_lint: names a valid, readable script path but the script exits non-zero, indicating the diff contains non-structural content.The plan reviewer (agents/qrspi-plan-reviewer.md § Schema-migration exception review) verifies all six conditions and emits a severity: high, change_type: correctness finding for each defect.
Before authoring any deliverable that operationalizes a design decision involving two or more actors — where "actor" means anything that performs an operation and hands off to another: scripts, subagents, orchestrators, tools, services, protocol participants, object-call participants, workflow steps, queue producers/consumers, function callers/callees — verify that the design specifies all six choreography elements:
If any element is missing for an in-scope decision, STOP authoring against this decision and surface a concrete diagnostic to the user. Do NOT guess the missing hand-off and continue.
Diagnostic template:
Design decision X enumerates actors A, B, C but does not specify [missing element — e.g., "what happens if B produces no output", "how A invokes B", "who reads C's output"].
Stopping before guessing.
Recommended path: trigger the Backward Loops procedure (see
using-qrspi/SKILL.md§ Backward Loops) to re-open Design via its per-decision dialogue, lock the missing element, re-review + re-approvedesign.md, then cascade forward — every dependent artifact from Design onward (Phasing if phase boundaries are affected, Structure, Plan, Parallelize if task dependencies are affected) re-runs against the updated design.Alternative: provide explicit guidance to accept the gap with a documented assumption recorded against this decision in the deliverable. The assumption becomes the de-facto contract — name what you are choosing for the missing element.
Iron law: silently inventing a missing hand-off is a contract violation that ships half-finished features which only surface at Test or in production. Guessing-instead-of-stopping is a process failure and must be reported even if the deliverable otherwise looks complete.
Inputs:
goals.mdresearch/summary.mddesign.mdstructure.mdTask: Break the structure into ordered tasks following vertical slices and phases.
design.mdPRECONDITION: skills/_shared/prompt-prose-detection.md, skills/_shared/prompt-prose-writer-addition.md, and skills/_shared/prompt-prose-test-expectations-clause.md MUST exist on disk; halt the subagent with a named diagnostic if any required shared file is missing rather than proceeding with empty include content.
Prompt prose is text authored to be loaded into an LLM's context as instructions, system prompts, agent definitions, skill definitions, reviewer rubrics, MCP tool descriptions, RAG instructions, or any equivalent LLM-consumable directive content.
Detection rule (universal). Use content semantics, not just file path or extension, as the determining signal. Ask: is the text intended to be loaded into an LLM's context at runtime as instructions? If yes, it is prompt prose, regardless of where it lives in the repo.
Path and extension as secondary signals (fast-path shortcut for qrspi-plus-internal authoring). When ALL target files match one of these globs, classify as prompt prose without further inspection:
skills/**/SKILL.mdskills/**/*.md (snippet files under a skill directory)agents/*.mdAGENTS.mdCLAUDE.mdFiles outside these globs require the content-semantic test above. Other projects may carry prompts in prompts/, src/llm-instructions/, or custom layouts — the content-semantic test is universal; the glob list is qrspi-plus-internal convenience only.
Examples of prompt prose:
agents/*.md file defining a subagent (role, task, constraints, tools)..md file under a project's prompts/ directory whose frontmatter description: indicates LLM consumption.<HARD-GATE> blocks)..txt or .json file whose content is plainly an LLM instruction payload.Examples of NOT prompt prose:
<!-- prose-design: ... --> marker indicates a verbatim prompt-prose block within).Rules file. When prompt-prose authoring or review applies, the rules live at skills/_shared/prompt-design-rules.md (resolved from the installed plugin path per host convention).
Writer-side application. When authoring or planning a deliverable, apply the detection above to the planned target content (or sub-block, for blocks within larger documents like design.md). If the target IS prompt prose, Read skills/_shared/prompt-design-rules.md (resolved from the installed plugin path per host convention) and apply R1-R7 + cross-cutting principles BEFORE drafting, not as post-write polish. The rules shape what to write; patching after the fact is a known anti-pattern. If the Read fails, do NOT proceed with authoring. Surface the error and stop.
If the target is NOT prompt prose (ordinary documentation, configuration, code, non-prompt prose), do NOT Read the rules file. Reading-without-applying is the verbosity-bias anti-pattern the rules themselves warn against — loading them into context for a deliverable they don't apply to wastes context and risks misapplication.
Test-Expectations clause for prompt-prose tasks. For tasks classified task_type: lightweight because the deliverable IS prompt prose (per the detection include above), Test Expectations cannot be RED-gate failing tests — prompt prose has no executable behavior to verify by test execution. Instead, encode rules-application as the verification mechanism using this template:
Implementer applies R1-R7 + cross-cutting principles from
skills/_shared/prompt-design-rules.md(resolved from the installed plugin path per host convention); reviewer (qrspi-code-quality-reviewerand/orqrspi-design-reviewerper surface in scope) verifies via the same content-semantic rules application; specific findings to verify: [task-specific list of R-rules or principles the deliverable must satisfy].
Other lightweight task categories (non-prompt prose, ordinary documentation, configuration) keep their existing Test-Expectations shape (presence / well-formedness / observable-behavior assertions as appropriate); only prompt-prose tasks carry the rules-application clause.
For small plans (<6 tasks): The overview subagent writes the full merged plan.md directly (overview + task specs in one document).
For large plans (6+ tasks): The overview subagent writes plan.md with only the overview section (phase structure, task ordering, dependency graph). Individual task specs are dispatched to sub-subagents.
When config.md has pipeline: quick:
goals.md and research/summary.md only (no design.md or structure.md)plan.md contains both the overview and the single task spectasks/task-01.md and plan.md is reduced to overview-only (same mechanics as full pipeline, but always exactly one task)The review round, human gate, and approval process are identical to full pipeline mode.
Compaction checkpoint: pre-fanout. Per-task spec-generation sub-subagent fan-out: one subagent per task; aggregate output is large and the orchestrator must hold all returned task files plus the merged plan.md for the upcoming review round. Saturated context at this site corrupts the single-source-of-truth invariant on merge. See using-qrspi ## Compaction Checkpoints for the iron-rule contract.
Call TaskCreate({ subject: "Recommend /compact (pre-fanout) — plan", description: "pre-fanout: per-task spec-generation fan-out; orchestrator merges all returned task files. User decides whether to /compact." }).
For large plans, farm task spec writing to sub-subagents:
Sub-subagent inputs:
plan.md overviewstructure.mddesign.md (for test strategy and vertical slice context)PRECONDITION: skills/_shared/prompt-prose-detection.md, skills/_shared/prompt-prose-writer-addition.md, and skills/_shared/prompt-prose-test-expectations-clause.md MUST exist on disk; halt the subagent with a named diagnostic if any required shared file is missing rather than proceeding with empty include content.
Prompt prose is text authored to be loaded into an LLM's context as instructions, system prompts, agent definitions, skill definitions, reviewer rubrics, MCP tool descriptions, RAG instructions, or any equivalent LLM-consumable directive content.
Detection rule (universal). Use content semantics, not just file path or extension, as the determining signal. Ask: is the text intended to be loaded into an LLM's context at runtime as instructions? If yes, it is prompt prose, regardless of where it lives in the repo.
Path and extension as secondary signals (fast-path shortcut for qrspi-plus-internal authoring). When ALL target files match one of these globs, classify as prompt prose without further inspection:
skills/**/SKILL.mdskills/**/*.md (snippet files under a skill directory)agents/*.mdAGENTS.mdCLAUDE.mdFiles outside these globs require the content-semantic test above. Other projects may carry prompts in prompts/, src/llm-instructions/, or custom layouts — the content-semantic test is universal; the glob list is qrspi-plus-internal convenience only.
Examples of prompt prose:
agents/*.md file defining a subagent (role, task, constraints, tools)..md file under a project's prompts/ directory whose frontmatter description: indicates LLM consumption.<HARD-GATE> blocks)..txt or .json file whose content is plainly an LLM instruction payload.Examples of NOT prompt prose:
<!-- prose-design: ... --> marker indicates a verbatim prompt-prose block within).Rules file. When prompt-prose authoring or review applies, the rules live at skills/_shared/prompt-design-rules.md (resolved from the installed plugin path per host convention).
Writer-side application. When authoring or planning a deliverable, apply the detection above to the planned target content (or sub-block, for blocks within larger documents like design.md). If the target IS prompt prose, Read skills/_shared/prompt-design-rules.md (resolved from the installed plugin path per host convention) and apply R1-R7 + cross-cutting principles BEFORE drafting, not as post-write polish. The rules shape what to write; patching after the fact is a known anti-pattern. If the Read fails, do NOT proceed with authoring. Surface the error and stop.
If the target is NOT prompt prose (ordinary documentation, configuration, code, non-prompt prose), do NOT Read the rules file. Reading-without-applying is the verbosity-bias anti-pattern the rules themselves warn against — loading them into context for a deliverable they don't apply to wastes context and risks misapplication.
Test-Expectations clause for prompt-prose tasks. For tasks classified task_type: lightweight because the deliverable IS prompt prose (per the detection include above), Test Expectations cannot be RED-gate failing tests — prompt prose has no executable behavior to verify by test execution. Instead, encode rules-application as the verification mechanism using this template:
Implementer applies R1-R7 + cross-cutting principles from
skills/_shared/prompt-design-rules.md(resolved from the installed plugin path per host convention); reviewer (qrspi-code-quality-reviewerand/orqrspi-design-reviewerper surface in scope) verifies via the same content-semantic rules application; specific findings to verify: [task-specific list of R-rules or principles the deliverable must satisfy].
Other lightweight task categories (non-prompt prose, ordinary documentation, configuration) keep their existing Test-Expectations shape (presence / well-formedness / observable-behavior assertions as appropriate); only prompt-prose tasks carry the rules-application clause.
Each sub-subagent writes tasks/task-NN.md. After all complete, the Plan skill reads all task files, appends them as sections to plan.md, then deletes the individual tasks/task-NN.md files — creating a single document as the only source of truth during review.
task_type and tier)Every task spec — whether emitted by the merged-plan subagent or by a per-task sub-subagent — must set task_type and tier in its frontmatter (the per-task model: routing field is retired by G22 / design.md CD-1). Assign them in this order, per task. These flags drive Implement-skill routing: task_type selects between the TDD implementer and the lightweight implementer; tier is consumed at the dispatch boundary by the Tier Resolution Chain (owned by scripts/_resolve-lib.sh), which maps the tier to a concrete (vendor, model) pair via config.md's model_routing: block — it is NOT a forwarded per-invocation model override.
task_type defaulting and dispatch-ordering note. The task_type field drives which Implement-skill dispatch chain fires for the task:
task_type: — defaults to the TDD path (test-writer dispatches before implementer, followed by the RED-verification gate; same behavior as task_type: code).task_type: code — TDD path: test-writer dispatches first (authoring failing tests), then the RED-verification gate runs, then the implementer dispatches to reach GREEN. Dispatch order: test-writer → RED gate → implementer.task_type: lightweight — lightweight-only dispatch: no test-writer, no RED gate. Implement dispatches qrspi-implementer-lightweight directly. Dispatch order: implementer only.Every per-task spec for a TDD task (task_type: code or absent) must carry an explicit dispatch-ordering note in its ## Description or at the top of ## Test Expectations so the Implement orchestrator reads the ordering without cross-referencing the plan classification section:
Dispatch order: test-writer first, implementer second (RED-verification gate between).
Specs for task_type: lightweight tasks omit this note (no test-writer, no RED gate).
Step 1 — Classify each task as code or lightweight. Default task_type: code.
Assign task_type: lightweight when the task's primary deliverable is prompt prose OR non-prompt prose / docs / config that has no executable behavior to test.
PRECONDITION: skills/_shared/prompt-prose-detection.md MUST exist on disk; halt the subagent with a named diagnostic if the shared file is missing rather than proceeding with empty include content.
Prompt prose is text authored to be loaded into an LLM's context as instructions, system prompts, agent definitions, skill definitions, reviewer rubrics, MCP tool descriptions, RAG instructions, or any equivalent LLM-consumable directive content.
Detection rule (universal). Use content semantics, not just file path or extension, as the determining signal. Ask: is the text intended to be loaded into an LLM's context at runtime as instructions? If yes, it is prompt prose, regardless of where it lives in the repo.
Path and extension as secondary signals (fast-path shortcut for qrspi-plus-internal authoring). When ALL target files match one of these globs, classify as prompt prose without further inspection:
skills/**/SKILL.mdskills/**/*.md (snippet files under a skill directory)agents/*.mdAGENTS.mdCLAUDE.mdFiles outside these globs require the content-semantic test above. Other projects may carry prompts in prompts/, src/llm-instructions/, or custom layouts — the content-semantic test is universal; the glob list is qrspi-plus-internal convenience only.
Examples of prompt prose:
agents/*.md file defining a subagent (role, task, constraints, tools)..md file under a project's prompts/ directory whose frontmatter description: indicates LLM consumption.<HARD-GATE> blocks)..txt or .json file whose content is plainly an LLM instruction payload.Examples of NOT prompt prose:
<!-- prose-design: ... --> marker indicates a verbatim prompt-prose block within).Rules file. When prompt-prose authoring or review applies, the rules live at skills/_shared/prompt-design-rules.md (resolved from the installed plugin path per host convention).
Apply the detection above to the planned target files. If the target IS prompt prose, classify lightweight. Mixed-deliverable tasks (one prompt-prose file + one code file in the same task) require ALL target files to satisfy the lightweight test; mixed tasks default to task_type: code — split per Goal-Specificity rules if genuinely mixed in nature.
The classification gates downstream behavior: lightweight tasks dispatch to qrspi-implementer-lightweight (which inherits its own prompt-prose detection via the prompt-prose-writer skill preload); code tasks dispatch to qrspi-implementer (TDD path). Prompt prose NEVER lands on the TDD path by classification.
Step 2 — tier. Run after task_type is set. Emits the per-task tier: frontmatter field consumed by the implementer dispatch (and co-escalated to the TDD test-writer dispatch); it supersedes the legacy per-task model: field (G22 / design.md CD-1).
task_type == lightweight → tier: low. No exception.task_type == code → tier: high if any of:
Target files count > 3 (multi-file architectural touch)skills/**/SKILL.md, skills/_shared/**, agents/qrspi-implementer*.md, agents/qrspi-implementer-lightweight*.md, skills/reviewer-protocol/**, skills/implementer-protocol/**fix_task_retry: true)sizing_exception (deliberately-bundled task in the closed exception set — schema migration, CI scaffolding, reusable primitives — higher uncertainty by construction)tier: medium.Operator override. The tier: field is editable by the operator before plan approval. The heuristic is a default, not a contract. A user who knows a single-file task is high-stakes can flip tier: high manually; a user who knows a 4-file task is mechanical can flip it back to tier: medium.
Defaults when fields are absent. Plan files that omit task_type: and tier: are read by Implement as code with default_tier: from config.md (medium) and a one-line warning at dispatch — no hard failure, no forced rewrite.
The output template below embeds information-mapping patterns directly: claim-before-evidence (the task title and Description's first sentence carry the load-bearing claim — what observable behavior the task delivers); one-paragraph-per-claim density (each bullet carries one claim, no compound bullets); scannable bullets and required headings (Phase / Target files / Dependencies / LOC estimate / Description / Test expectations are required structural slots, not optional prose); no "be concise" instructions (research-backed: brevity directives degrade factual reliability per the Phare benchmark and Hakim). Per-task specs are short by structural design (terse bullets, no narrative), not by an explicit brevity instruction.
Any artifact in the QRSPI run directory governed by status: draft → approved frontmatter promotion (goals, design, structure, phasing, plan, parallelization, roadmap, future-goals, and any future artifact adopting this lifecycle) describes the current state of decisions. The reader is a downstream agent or future maintainer.
(Excludes by design: SKILL.md files — skills carry rule rationale legitimately; feedback/*.md — the designated home for dialogue exhaust; reviews/**/*.md — finding rationale; config.md — non-narrative.)
Litmus test (apply to every paragraph before write). Two filters, in order:
A sentence that only makes sense as a delta from a prior state is dialogue exhaust — strip it.
Permitted substantive content (do NOT confuse with dialogue exhaust):
## Trade-offs Considered — substantive content about the decision space, not about the document's history)Named antagonist patterns — strip on sight, substitute as shown:
| Antagonist pattern | Recognize by | Replace with | |---|---|---| | Session / drafting notes | "Rule X drafting note," "this collapsed from 3 to 1 because…" | Nothing — delete. If a fact matters, embed inline in the decision. | | Version-history narration | "earlier draft said X," "previously," "originally," "pre-cleanup" | Nothing — git history holds versions. | | Inside baseball | text addressed to "us" / "the author," meta-explanation of the document's own structure ("this section is split into A and B because…") | The decision the structure expresses — without the structural explanation. | | Compaction-loss recovery notes | "this nuance was almost lost during…" | Nothing — if the nuance is needed, the rule itself carries it. | | Failure-modes-prevented lists | bullets that justify why a rule exists rather than state what to do | Strengthen the rule's wording; delete the justification list. |
Decision-process history (drafts, review rounds, feedback applied, compaction recovery) lives in feedback files, review findings, PR descriptions, and git history — never in the artifact.
---
status: draft
phase_start_commit: null
test_writer_tier: null # optional. one of: low | medium | high. When unset, the per-task `tier:` drives the co-escalated qrspi-test-writer dispatch (high-tier tasks co-escalate implementer + test-writer to the same tier per design.md CD-1). Set explicitly only to pin the test-writer tier independent of per-task tier.
---
# Implementation Plan
## Overview
{Phase structure, task ordering, dependency graph — claim first, then supporting structure}
## Phase 1: {name}
{Tasks in this phase, ordering rationale — one paragraph per claim, scannable bullets}
### Phase 1 Acceptance Criteria
Per-phase criteria that must be observable end-to-end at phase boundary (independent of any single task):
- [ ] {Criterion 1: e.g., "Full PoC slice demonstrates request → response with rate limiting active"}
- [ ] {Criterion 2: ...}
(Per-task criteria live in each `tasks/task-NN.md`'s `## Test Expectations` block; the per-phase block above captures cross-task observable behavior at phase end.)
## Phase 2: {name}
{Tasks in this phase, ordering rationale}
### Phase 2 Acceptance Criteria
Per-phase criteria observable at this phase's boundary (same authoring rules as Phase 1):
- [ ] {Criterion 1: ...}
- [ ] {Criterion 2: ...}
---
## Task Specs
### Task 1: {name — names exactly one observable behavior; no `+` joining feature names; no two distinct verbs joined by `and`}
- **Phase:** 1
- **Target files:** {exact paths, create/modify}
- **Dependencies:** none
- **LOC estimate:** ~{N}
- **Sizing exception:** {only present when the task is a legitimate bundle (multi-handler or >200 LOC). Reason must be one of: schema migration, CI scaffolding, reusable primitives — see Task Sizing}
- **Description:** {what this task accomplishes — claim-before-evidence: lead with the observable-behavior sentence, then supporting context. Plain language; no function signatures (→ Structure); no algorithm pseudocode (→ Implement); no architecture rationale (→ Design).}
- **Test expectations:**
- {behavior 1 — plain language; no `expect(...)` or assertion code (→ Implement-TDD)}
- {edge case 1}
- {error condition 1}
### Task 2: {name}
...
Per-phase acceptance block authoring (strip-from-goals contract). Per-phase acceptance criteria capture cross-task observable behavior at phase end — they must trace upstream to one or more goals.md goals but they are AUTHORED in plan.md, not goals.md (per the strip-from-goals contract). The per-phase block lives directly under each ## Phase N: {name} heading as a ### Phase N Acceptance Criteria subsection (see template above). Downstream consumers (test/SKILL.md, the qrspi-plan-spec-reviewer agent body, the qrspi-plan-goal-traceability-reviewer agent body) read these blocks to verify end-to-end observable behavior at phase boundary independent of any single task; per-task criteria continue to live in each task spec's ## Test Expectations block below.
Conformance reminder for the per-task spec writer. Each task spec must satisfy: required-section presence (every bullet header above is required); claim-line length ≤ 250 chars per bullet; description paragraph ≤ 150 words; section ≤ 300 words total before bullets are split; no brevity directives anywhere ("be concise", "brief summary", "≤ N lines" are forbidden — see the lint allowlist for the legitimate length-target exceptions). The DEFERS list above tells the writer what NOT to put in the spec; this conformance reminder tells the writer how to structure what they DO put in.
Smoke-check requirement. Any task adding or modifying a route, page, layout, or user-facing component MUST include a smoke_checks: block per the smoke-spec convention (smoke-spec.md). Tasks that only modify internal libraries (no route or component surface) MAY omit it.
Every plan declares the commands the implementer gate uses to verify a task:
build_command — the command that produces the project's build artifact, run after tests pass during per-task verification. Examples: pnpm build (Next.js, Vite), cargo build --release, go build ./..., tsc -p . (lib-only). Set to the literal string 'none' only for pure-script projects with no build step; include a one-line rationale next to the field when set to 'none'.dev_command — the command that starts the dev server, used by the smoke-check gate. Required when any task in the plan declares a smoke_checks: block; optional otherwise. Examples: pnpm dev, cargo run, python manage.py runserver. Plans that opt into smoke checks also declare smoke_auth: per smoke-spec.md.The implementer reads these from the plan and runs them at the per-task gate (see skills/implement/SKILL.md).
Seven reviewer dispatches run in parallel as part of the review round (one unified plan-quality reviewer + five plan-artifact reviewers + one scope-reviewer). All seven run always — neither quick-fix nor full-pipeline mode gates any reviewer. Plan-artifact reviewers that require design.md or structure.md emit "NOT APPLICABLE — quick-fix route" for those checks when those files are absent (the route dispatch param tells each agent which checklist to run).
Plan-artifact reviewers vs per-task reviewers. The five plan-artifact reviewers below review the plan artifact against goals/research/design/structure (gap analysis, scope creep, placeholder detection, etc.). They are distinct from the per-task reviewers dispatched during Implement (which review task implementations against the task spec). The agent files share base names but the bodies and dispatch sites differ — plan-artifact reviewers live at
agents/qrspi-plan-{name}.md; per-task reviewers live atagents/qrspi-{name}.md.
| Reviewer | Agent | Focus | Run Condition |
|----------|-------|-------|---------------|
| Plan Quality (unified) | qrspi-plan-reviewer | Cross-cutting plan-quality (completeness, no-placeholders, sizing, phase alignment, design/structure traceability on full route) | Always |
| Spec Reviewer | qrspi-plan-spec-reviewer | Completeness, scope, interpretation, test coverage mapping, placeholder detection | Always |
| Security Reviewer | qrspi-plan-security-reviewer | Fail-closed requirements, input validation, auth/authz, no insecure defaults | Always |
| Silent Failure Hunter | qrspi-plan-silent-failure-hunter | Swallowed errors, silent fallbacks, partial state on failure, log-and-continue | Always |
| Goal Traceability Reviewer | qrspi-plan-goal-traceability-reviewer | Forward trace, backward trace, gap analysis, spec-to-design fidelity | Always |
| Test Coverage Reviewer | qrspi-plan-test-coverage-reviewer | Behavioral coverage, edge cases, error conditions, test expectation quality, missing design scenarios | Always |
| Scope Reviewer | qrspi-plan-scope-reviewer | OWNS/DEFERS boundary-drift detection per ## Plan OWNS / Plan DEFERS below; scope-compliance per locked Plan rules | Always |
Compaction checkpoint: pre-fanout. Reviewer fan-out reads merged plan.md + goals.md + research/summary.md + design.md + structure.md; up to seven parallel Claude dispatches (unified quality + five plan-artifact + scope) plus seven non-blocking Codex parallels when codex_reviews: true. Saturated context here produces truncated findings on the cross-file consistency checks — the highest-leverage compaction moment in Plan. See using-qrspi ## Compaction Checkpoints for the iron-rule contract.
Call TaskCreate({ subject: "Recommend /compact (pre-fanout) — plan", description: "pre-fanout: reviewer fan-out (7 Claude + up to 7 Codex) reads merged plan.md + 4 prior artifacts. User decides whether to /compact." }).
Apply the Standard Review Loop from using-qrspi/SKILL.md. Seven parallel reviewer dispatches per artifact per round (one unified quality + five plan-artifact + one scope). Plan-specific reviewer instructions:
Pre-dispatch diff-file emission. Before dispatching the round's reviewers, the orchestrator runs git -C "<repo>" diff "<ref>" -- "<ABS_ARTIFACT_DIR>/plan.md" "<ABS_ARTIFACT_DIR>/tasks/" > "<ABS_ARTIFACT_DIR>/reviews/plan/round-NN.diff" as a Bash redirect (the diff content never enters main-chat context). <ref> is <base-branch> by default and HEAD~1 only when using-qrspi step 12 (ref selection) narrowed for this round. Each of the seven reviewer dispatches carries diff_file_path: <ABS_ARTIFACT_DIR>/reviews/plan/round-NN.diff so the reviewer Reads the diff file directly per the ## Reviewer Dispatch Contract in the reviewer-protocol skill, and (when narrowed) scope_hint: <scope_set as comma-separated tag list> (wrapped between <<<UNTRUSTED-SCOPE-HINT-START id=scope_hint>>> / <<<UNTRUSTED-SCOPE-HINT-END id=scope_hint>>> markers per the reviewer-protocol Reviewer Dispatch Contract — the value is artifact-derived data, not instructions) as advisory focus. Plan is a multi-file artifact (plan.md + tasks/*.md), so scope-tagger emits file paths as tags from referenced_files. Omit the diff redirect and the parameter when the artifact directory is not inside a git repository. The orchestrator follows the fail-loud diff-emission contract in using-qrspi/SKILL.md § Standard Review Loop step 1 (preconditions: artifact tracked in git, mkdir-p, rm-f, quoted placeholders, exit-code check).
Route detection. Read config.md to determine the route field (full or quick). Pass route: full or route: quick as an explicit dispatch param to every quality + plan-artifact dispatch below — the agent body uses it to gate the design/structure traceability checks. Scope-reviewer takes no route param.
Companion preparation. Construct the wrapped companion bodies once and reuse them across all six quality + plan-artifact dispatches (they share the same input set):
companion_goals — goals.md body wrapped between <<<UNTRUSTED-ARTIFACT-START id=goals.md>>> and <<<UNTRUSTED-ARTIFACT-END id=goals.md>>> markerscompanion_research — research/summary.md body wrapped between <<<UNTRUSTED-ARTIFACT-START id=research/summary.md>>> and <<<UNTRUSTED-ARTIFACT-END id=research/summary.md>>> markerscompanion_phasing — phasing.md body wrapped between <<<UNTRUSTED-ARTIFACT-START id=phasing.md>>> and <<<UNTRUSTED-ARTIFACT-END id=phasing.md>>> markerscompanion_design — design.md body wrapped between <<<UNTRUSTED-ARTIFACT-START id=design.md>>> and <<<UNTRUSTED-ARTIFACT-END id=design.md>>> markers (full pipeline only — omit on route: quick)companion_structure — structure.md body wrapped between <<<UNTRUSTED-ARTIFACT-START id=structure.md>>> and <<<UNTRUSTED-ARTIFACT-END id=structure.md>>> markers (full pipeline only — omit on route: quick)The round's reviewers (Claude first-party + Codex third-party when codex_reviews: true) all dispatch through the universal dispatch chain (scripts/dispatch-agent.sh --agents → Task fan-out → scripts/await-round.sh). *-claude tags route to the first-party Task path; *-codex tags route to the third-party companion path. Include the *-codex peer tags in REVIEW_AGENTS only when codex_reviews: true; on quick-fix routes the dispatcher omits companion_design/companion_structure automatically. Set the per-skill dispatch parameters, then include the shared reviewer-dispatch prose:
REVIEW_STEP="plan"
REVIEW_ROUND="${ROUND}" # current review round (NN)
REVIEW_OUTPUT_DIR="<ABS_ARTIFACT_DIR>/reviews/plan/round-${ROUND}/"
REVIEW_ARTIFACT="plan.md"
REVIEW_AGENTS="quality-claude=qrspi-plan-reviewer,spec-claude=qrspi-plan-spec-reviewer,security-claude=qrspi-plan-security-reviewer,silent-failure-claude=qrspi-plan-silent-failure-hunter,goal-traceability-claude=qrspi-plan-goal-traceability-reviewer,test-coverage-claude=qrspi-plan-test-coverage-reviewer,scope-claude=qrspi-plan-scope-reviewer,quality-codex=qrspi-plan-reviewer,spec-codex=qrspi-plan-spec-reviewer,security-codex=qrspi-plan-security-reviewer,silent-failure-codex=qrspi-plan-silent-failure-hunter,goal-traceability-codex=qrspi-plan-goal-traceability-reviewer,test-coverage-codex=qrspi-plan-test-coverage-reviewer,scope-codex=qrspi-plan-scope-reviewer"
With $REVIEW_STEP, $REVIEW_ROUND, $REVIEW_OUTPUT_DIR, $REVIEW_ARTIFACT, and $REVIEW_AGENTS set by the per-skill preamble above, run:
scripts/dispatch-agent.sh --step "$REVIEW_STEP" --round "$REVIEW_ROUND" \
--output-dir "$REVIEW_OUTPUT_DIR" --artifact "$REVIEW_ARTIFACT" \
--agents "$REVIEW_AGENTS"
dispatch-agent emits M lines on stdout (one per first-party reviewer; zero lines for a third-party-only batch). Each line has the form:
MODE=first_party TAG=<tag> SUBAGENT_TYPE=<agent-name> MODEL=<resolved-model> PROMPT_FILE=<absolute-path>
For every emitted spec line, invoke the Task tool with these arguments (parse the line as space-separated KEY=VALUE pairs; values contain no spaces):
subagent_type = the SUBAGENT_TYPE value, verbatimmodel = the MODEL value, verbatimprompt = the literal string "DISPATCH_FILE=<PROMPT_FILE-value>" — a single-line env-var-style reference; the prompt argument has no other contentInvoke all M Task tool calls in parallel in one orchestrator response (one Task call per spec line). The reviewer agent body's first instruction is to Read its DISPATCH_FILE — do not pre-Read the file yourself; the dispatch context belongs in the subagent's window, not the orchestrator's.
Iron law (orchestrator-side dispatch contract): invoke the Task tool exactly once per emitted spec line, with SUBAGENT_TYPE, MODEL, and PROMPT_FILE copied verbatim. Skipping a line, deduplicating across lines, modifying any value, or substituting a different subagent_type is a contract violation. The dispatch manifest ($REVIEW_OUTPUT_DIR/.dispatch-manifest.json) records expected dispatches; the apply-fix step's "expected tag produced no output" diagnostic catches missed or mis-routed Task invocations.
After all Task tool calls return (Task tool is synchronous; first-party subagents have written their per-finding files to disk by the time Task returns), drain any third-party background dispatches and finalize the round:
scripts/await-round.sh --round-dir "$REVIEW_OUTPUT_DIR"
await-round is no-op-safe — first-party-only rounds still call it; it returns immediately after reading the manifest. It writes a small $REVIEW_OUTPUT_DIR/.round-complete.json summary and (for third-party dispatches) materializes per-finding files via third-party-finding-splitter.sh. It does NOT echo captured subagent payloads (CD-1 #4 output-bound contract).
Then read $REVIEW_OUTPUT_DIR/.round-complete.json and the per-finding files as needed for apply-fix. The raw per-reviewer prompt content (assembled by dispatch-agent into PROMPT_FILE) never enters the orchestrator's context — only the small spec lines + the small DISPATCH_FILE references passed to Task.
Present merged plan.md to the user — overview for approval, task details for spot-checking. Always state the review status when presenting: either "Reviews passed clean in round N" or "Reviews found issues in round N which were fixed but not re-verified."
On approval:
If reviews have NOT passed clean (the user chose option 1 earlier, or backward loops introduced changes after the last clean round): Ask the user before proceeding: "Reviews haven't passed clean yet. Would you like me to run a review loop to clean before splitting? This is strongly recommended — the review cycle catches cross-file inconsistencies that are hard to spot manually." If the user agrees, run the review loop (same as option 2 above), then continue. If they decline, proceed.
Recommend compaction before splitting: "Plan approved. This is a good point to compact context (/compact) before I split tasks into individual files — the split is mechanical and doesn't need the full conversation history." Wait for the user to compact (or decline), then proceed.
Split (post-approval orchestration): Fan out per-task spec writing, verify file set, reduce plan.md to overview-only, capture phase_start_commit:, then write status: approved — in this exact transactional order, so an approved plan.md is never observable on disk without all corresponding tasks/task-NN.md files present.
The formal per-sub-subagent input/output contract for the fan-out — including the wrapped task-section payload shape, the canonical task-file template, the G7 ID-hygiene contract, the exactly-one-file-per-dispatch output clause, the no-plan.md-edits clause, and the atomicity contract on partial returns — lives in skills/plan/post-approval-split-contract.md. This skill section is the orchestration site; the contract document is the single source of truth for the dispatch shape.
N-threshold carve-out. Let N = the number of tasks in the approved plan.md overview.
N >= 3 (sub-subagent fan-out): Dispatch one sub-subagent per task in parallel. Each sub-subagent receives:
plan.md (the single ### Task NN: {name} block), wrapped as an untrusted artifact.tasks/task-NN.md format from the "Split task file format" section above), carrying all T24 Slice 5 frontmatter fields: reference_gate:, reference_artifact:, ui:, lift_source:, plus conditional: and conditional_precondition: (the T43 conditional-dispatch fields). Sub-subagents must carry these fields verbatim into the emitted tasks/task-NN.md frontmatter exactly as authored in the plan.goal_ids field is metadata; do NOT echo IDs into the task body prose).output_path: the absolute path to write (<artifact_dir>/tasks/task-NN.md).
Each sub-subagent writes exactly one tasks/task-NN.md file. Sub-subagents MUST NOT edit plan.md. This is the generation-side sub-subagent dispatch shape reused from ### Sub-Subagent Dispatch (Large Plans Only) above.
Rationale: sub-subagent dispatch overhead is justified at N >= 3 because the context saving from parallelism and isolation exceeds the per-dispatch overhead; combined plan + specs for N >= 3 tasks exceeds the 600-line threshold from design line 157 at which main-chat inline writing saturates the review window.N <= 2 (inline main-chat split): Write both tasks/task-01.md and tasks/task-02.md (or just tasks/task-01.md for a single-task plan) directly in main chat without dispatching sub-subagents. Combined plan + specs for N <= 2 tasks is estimated at under 600 lines per design line 157; sub-subagent dispatch overhead exceeds the context saving below this threshold.
File-count verification (exact-set check, applies to both paths). After the fan-out (or inline write) completes, verify the exact set of tasks/task-NN.md files present. The expected set is {task-01.md, task-02.md, ..., task-N.md} with no gaps and no duplicates. Do NOT pass this check by counting files alone — enumerate the actual IDs:
task-NN identifier (e.g., two sub-subagents both wrote tasks/task-03.md). HALT with a named diagnostic listing the duplicated IDs: "Split verification failed: duplicate task file(s) detected: task-03.md (2 copies). Resolve before proceeding." Do NOT write status: approved.task-04.md was not written). HALT with a named diagnostic listing the missing IDs: "Split verification failed: expected task files not written: task-04.md. Re-run split for missing tasks before proceeding." Do NOT write status: approved.
Only when the exact set matches — every expected ID is present exactly once — proceed to the next step.After passing verification: reduce plan.md to overview-only (remove the ## Task Specs section and all ### Task NN blocks — they now live in tasks/). Then capture phase_start_commit: in plan.md frontmatter (see ### phase_start_commit capture at approval time below). Then write status: approved in plan.md frontmatter.
On rejection: Write the user's feedback and the rejected artifact snapshot to feedback/plan-round-{NN}.md (using the standard feedback file format from using-qrspi), then launch a new subagent with original inputs + all prior feedback files (not just the latest round). After re-generation, the review cycle restarts from the beginning (the "loop until clean" choice applies to the new round).
When config.md carries pipeline: quick, the human-approval gate is skipped after any review round (initial or post-fix) that produces zero kept findings. When this branch fires, the split, status: approved write, and phase_start_commit capture proceed automatically without waiting for user input.
Verifier-gate precondition. "Zero kept findings" is satisfied only when the verifier has affirmatively confirmed the count — a vacuously-zero count from an undispatched verifier does NOT satisfy the gate and surfaces the round to the user as unverified (matching the HARD-GATE contract in skills/implement/SKILL.md). If config.md is missing or unreadable when this branch is evaluated, the auto-approve branch does NOT fire — the orchestrator surfaces a named diagnostic and falls through to the standard human-approval gate (fail-loud, not silent fallback to either pipeline mode). The gate passes when ANY of the following hold for the current round's directory (reviews/plan/round-NN/):
.score.yml sidecar file exists in the round directory AND every sidecar evaluates to no kept-blocker findings per the verifier's scoring rubric (see agents/qrspi-finding-verifier.md and skills/implementer-protocol/SKILL.md). A zero-byte sidecar does not constitute verifier affirmation and the gate does NOT pass. Full sidecar schema validation is the verifier's contract (see agents/qrspi-finding-verifier.md); this skill assumes well-formed sidecars. ORround-NN-verifier-disabled.md marker file is present in the round directory AND the marker conforms to the canonical schema defined in skills/implement/SKILL.md HARD-GATE (a marker failing schema validation, or whose round identifier does not match the current round, is treated as absent). ORconfig.md carries verifier_enabled: false. When this condition satisfies the gate, the orchestrator MUST append an audit-log entry before writing the split, status: approved, and phase_start_commit capture — recording: timestamp, run slug, step name (plan), and branch label (auto-approve-verifier-disabled-config). The audit entry is written to the cascade audit log if one exists, otherwise to the round directory. An attempt to auto-approve via verifier_enabled: false without successfully writing this audit entry MUST abort with a named diagnostic (fail-loud, matching the audit-write precondition philosophy in skills/implement/SKILL.md HARD-GATE). This path is a deliberate operator-level configuration, not a default; the round appears in the review log as verifier-disabled, not as a normal clean round.When none of these hold (no sidecars with affirmative zero-kept-findings content, no valid schema-conforming marker for the current round, and verifier_enabled is absent or true), the gate does NOT fire; the review round surfaces to the user as unverified and the standard human-approval gate runs.
Post-fix round behavior. If a fix round still produces kept findings, the auto-approve branch does NOT fire. The orchestrator surfaces the remaining kept findings to the user. The branch fires only when the most recent review round — initial or post-fix — produces verifier-affirmed zero kept findings.
Relationship to existing single-task plan behavior. The auto-approve branch supplements the quick-fix single-task plan behavior already documented in § Quick-Fix Plan Behavior. The single-task plan constraint continues to apply; the auto-approve branch adds only the conditional skip of the human-prompt step at the end of the existing approval flow.
Full pipeline unchanged. When pipeline: full, the human-approval gate runs as before — the branch is inert and the user must explicitly approve.
tasks/task-NN.md files → Plan skill reads all task files, appends them as sections to plan.md, then deletes the individual tasks/task-NN.md files → single document is the only source of truth during review. For small plans (<6 tasks), the plan subagent writes the merged plan.md directly.plan.md — tasks/ directory is empty, no dual source of truth.### Task N section back into tasks/task-NN.md files, then reduces plan.md to overview-only (removing the appended task specs). No duplication.Split task file format (tasks/task-NN.md):
---
status: approved
task: NN
phase: {phase number}
pipeline: full
goal_ids: [G1, G2] # QRSPI-internal traceability metadata — see ID-Hygiene Contract below
task_type: code # one of: code | lightweight. default: code. See "Per-Task Classification" below.
tier: medium # one of: low | medium | high. default: medium. See "Per-Task Classification" below.
# Optional: justify a legitimate bundle (multi-handler or >200 LOC).
# Reason must be one of: schema migration, CI scaffolding, reusable primitives.
# sizing_exception: <one-line reason>
# (Target files are aspirational; deviation discipline lives in the per-task
# spec reviewer.)
#
# Optional reference-gate binding. MANDATORY pair: when reference_gate: true is
# set, reference_artifact must also be set; Plan refuses to write the task spec
# when the pair is incomplete (see Refuse-to-Write Contract below).
# reference_gate: true
# reference_artifact: path/to/source-of-truth.md # required when reference_gate: true
#
# Optional UI flag. When ui: true is set, the task emits user-visible UI output.
# When ui: true AND lift_source: <path> are both set, the task body MUST include
# a SPEC OVERRIDES SOURCE section (see SPEC OVERRIDES SOURCE below).
# ui: true
# lift_source: path/to/existing-source.md # optional; pair with ui: true
#
# Optional visual-fidelity binding block. MANDATORY only on UI-producing tasks
# when `config.md` carries `visual_fidelity_required: true`; otherwise omit the
# whole block. The Plan orchestrator's pre-fanout hard-gate (see "Red Flags"
# below) consumes these fields to refuse plan-review dispatch when a
# UI-producing task lacks wireframe citations.
# visual_fidelity_check:
# wireframe_refs: # one entry per cited wireframe artifact
# - <path-or-URL-to-wireframe>
# ui: true # true on tasks that emit UI output, false otherwise
# # (replaces the legacy ui_producing field — see Migration below)
---
# Task NN: {name}
- **Target files:** {exact paths, create/modify}
- **Dependencies:** {task numbers or "none"}
- **LOC estimate:** ~{N}
- **Description:** {what this task accomplishes — substantive WHY only; no ID echoes (see ID-Hygiene Contract below)}
- **Test expectations:**
- {behavior 1}
- {edge case 1}
- {error condition 1}
<!-- SPEC OVERRIDES SOURCE section — REQUIRED when frontmatter carries both
ui: true and lift_source: <path>. List behaviors the implementer must NOT
copy from the source and the required target behavior for each.
Omit this section when lift_source: is absent. -->
When a per-task spec is authored in plan.md (or in a split tasks/task-NN.md produced by sub-subagent fan-out), that spec is the authoritative definition of the task's behavior. If a source file referenced by lift_source: carries frontmatter or body content that conflicts with the per-task spec — including a stale visual_fidelity_check.ui_producing field, a legacy lift_source value, or any field that contradicts the spec's stated behavior — the spec wins. The implementer rewrites the source to match the spec, not the reverse.
This authority statement is load-bearing for every Slice 5 consumer: Structure (T25), Parallelize (T26), Implement (T27), the visual-fidelity reviewer (T28), and the reviewer-protocol/design-skill checklist (T29) all key on the per-task spec's frontmatter shape. When a source file's stale frontmatter disagrees with a spec's ui: true or reference_gate: true declaration, the implementer applies the spec's value and drops the source's conflicting field.
The Plan orchestrator refuses to write (or materialize post-approval) a task spec when either paired-field invariant is violated:
Pair 1 — Reference-gate pair:
reference_gate: true is present in the task spec AND reference_artifact: is absent → refuse, surface: "Plan refuse-to-write: task NN carries reference_gate: true without reference_artifact — add reference_artifact: <path> or remove reference_gate."reference_artifact: is present AND reference_gate: true is absent → refuse, surface: "Plan refuse-to-write: task NN carries reference_artifact without reference_gate: true — add reference_gate: true or remove reference_artifact."Pair 2 — UI+lift-source pair:
ui: true AND lift_source: <path> are both present AND the task body contains no SPEC OVERRIDES SOURCE section → refuse, surface: "Plan refuse-to-write: task NN carries ui: true and lift_source: <path> without a SPEC OVERRIDES SOURCE body section — add the section listing behaviors not to copy and required target behavior."Multiple violations in one plan are reported together before any task spec is written, so the author fixes them in a single pass. The refusal applies both to initial plan authoring and to the post-approval sub-subagent materialization of tasks/task-NN.md files.
Task specs with none of reference_gate:, reference_artifact:, ui:, or lift_source: are written and processed without error, produce no paired-field diagnostic, trigger no reference-gate pause, and trigger no visual-fidelity reviewer dispatch — behaving identically to a pre-Slice-5 task spec.
visual_fidelity_check.ui_producing → top-level ui:Pre-Slice-5 task specs may carry a visual_fidelity_check.ui_producing: true field. When Plan encounters this field in a task spec during review or post-approval split:
ui: true field in the task frontmatter.ui_producing field from inside the visual_fidelity_check: block.visual_fidelity_check: sub-fields (e.g., wireframe_refs:) unchanged.This is the one replacement-not-additive field change in Slice 5 per design Decision 10. After migration, the visual_fidelity_check: block no longer carries ui_producing; the canonical ui: top-level field is the single source of truth for whether a task emits UI output.
ID-Hygiene Contract. QRSPI-internal traceability lives in the YAML frontmatter goal_ids field — the metadata block the implementer subagent reads but does NOT echo into the work product. The canonical surface list (strict surfaces and the comment/test split rule) lives in agents/qrspi-implementer.md § ID Hygiene and is reviewed by agents/qrspi-code-quality-reviewer.md § 11; this contract defers to those sites rather than re-enumerating, so the surface list has a single source of truth. Plan's responsibility here is upstream: do NOT add Target satisfies:, Goals addressed:, Closes <goal-ID>, per <decision-ID>, or similar QRSPI-internal-ID-bearing prose to the body of the task spec — those phrasings invite the implementer to copy IDs into the work product. The body's Description, Test expectations, and supporting bullets must read as standalone work specifications grounded in observable behavior; goal traceability is a metadata concern, not a body concern. PR-body Closes #N (external tracker IDs only) remains valid at commit/PR altitude.
The pipeline field is copied from config.md's pipeline value at plan time. The per-task dispatch in implement/SKILL.md § Per-Task Execution reads the task file's pipeline field for per-task input gating (which artifacts to load for the task's review context). The Implement skill itself derives run mode separately from config.md.route for its per-phase orchestration — see implement/SKILL.md § Overview.
Who writes the pipeline field:
config.md onto every tasks/task-NN.md at plan timefull on integration/CI fix tasksconfig.md.route per implement/SKILL.md § Overview) on task-00 (pipeline: full in full-pipeline runs, pipeline: quick in quick-fix runs) so the per-task input gating matches the artifacts that exist. Implement writes the runtime-injected task-00.md with status: approved so the Iron Law gate passes on dispatch.Fix task files also include a fix_type field (not present on regular tasks):
fix_type: integration — written by Integrate for cross-task integration fixesfix_type: ci — written by Integrate for CI pipeline fix tasksfix_type: test — written by Test for acceptance test fix tasksFix tasks are stored in fixes/{type}-round-NN/ and follow the same format as regular tasks so the Implement skill can process them identically.
plan.md — complete plan with overview + all task specs (review artifact), overview-only after approvaltasks/task-NN.md — individual task specs split out after approval (implementation artifacts)phase_start_commit capture at approval timeAt plan.md approval time, capture the current HEAD SHA into plan.md frontmatter's phase_start_commit: field. This is the diff anchor Replan and Test use to scope post-phase changes.
Implementation: when the user approves plan.md, run git -C <artifact_dir> rev-parse HEAD (or the closest enclosing git repo if the artifact dir isn't itself a repo). Write the SHA into the frontmatter alongside status: approved, then commit per the standard "commit after approval" rule. If the artifact dir is not in a git repo, leave phase_start_commit: null — Replan and Test fall back to whole-codebase scope.
Verification fallback (debug only): if the frontmatter value is missing or suspect, the SHA can be derived from git -C <repo> log -1 --format=%H -- <artifact_dir>/plan.md. This is the non-git fallback path for runs where the frontmatter wasn't populated; the frontmatter is the primary store.
If the artifact directory is inside a git repository, commit the approved plan.md, all tasks/task-NN.md files, and the reviews/plan/ directory (per-round per-reviewer files; see using-qrspi → "Commit after approval (when applicable)").
Compaction checkpoint: pre-handoff. Plan has just split tasks into individual files and committed the approved artifacts; conversation history from the synthesis + review rounds is no longer load-bearing. The next skill (typically Parallelize) reads the artifacts on a fresh context for dependency-graph reasoning. See using-qrspi ## Compaction Checkpoints for the iron-rule contract.
Call TaskCreate({ subject: "Recommend /compact (pre-handoff) — plan", description: "pre-handoff: next skill reads plan.md + tasks/*.md on a fresh context; review history no longer load-bearing. User decides whether to /compact." }).
REQUIRED: Invoke the next skill in the config.md route after plan.
If compaction was not done before splitting (user declined), recommend it now: "This is a good point to compact context before the next step (/compact)."
Each per-task spec carries a **Test expectations:** bullet list naming the observable behaviors, edge cases, and error conditions the implementer must cover (see the per-task template above and § Quick-Fix Plan Behavior for the standard authoring shape). The bullets describe behavior in plain language; the Test skill and the implementer's TDD cycle consume them as the source of truth for which tests must exist before implementation lands.
The standard bullet shape covers the common case where every test the producing task must satisfy lives inside the task's Target files:. Sweep tasks — tasks that systematically remove, replace, or enforce an invariant across many files at once — break this assumption: the test files that assert on the swept property's previous values are not in the producing task's files_in_scope, so the per-task gate never runs them, the task ships GREEN, and the integrate phase surfaces stale-test failures the producing task should have owned. The subsection below closes that gap by requiring sweep-task plan-spec authors to enumerate dependent tests at plan-authoring time.
A sweep task removes, replaces, or enforces an invariant across many files at once (e.g., "strip model: from all agent frontmatter," "rename qrspi-foo to qrspi-bar across all skills," "remove all ${VAR} references in CDs"). Sweep tasks systematically invalidate test files that assert on the swept property's previous values, even when those test files are not in the task's files_in_scope.
A sweep-task plan-spec MUST include, in its Test Expectations block, a dependent_tests: field with one of two values:
none followed on the next line by a grep-confirmable search command of shape grep -rn -- '<pattern>' tests/ that demonstrably returns zero matches. The pattern is the swept identifier (e.g., '^model:') — the plan-reviewer will re-run the grep and surface a finding if it returns one or more hits.Skipping the dependent_tests: field on a sweep-shaped task is a plan-spec defect, not a deferred-to-implementer concern. The Plan reviewer (agents/qrspi-plan-reviewer.md § Sweep-task detection) detects sweep-shaped tasks by heuristic (>5 same-extension files in files_in_scope plus one of eight sweep keywords in the title or description, case-insensitive word-boundary match) and emits a severity: high, change_type: correctness finding when the field is missing or malformed.
Worked example A — explicit dependent test path list with per-file dispositions. A sweep task that strips model: from all 41 agent frontmatter files lists every test that asserts on the previous model: values, with a one-sentence disposition per file:
- **Test expectations:**
- All 41 agent files have `model:` removed from frontmatter; no other frontmatter fields change.
- `dependent_tests:`
- `tests/unit/test-scope-tagger-dispatch.bats` — currently asserts `model: opus` on line 38; update to assert `model:` is absent post-sweep.
- `tests/unit/test-verifier-agent-file.bats` — currently asserts `model: sonnet` on line 7; update to assert `model:` is absent post-sweep.
- `tests/unit/test-visual-fidelity-reviewer-agent.bats` — currently asserts a specific model value on line 35; update to assert `model:` is absent post-sweep.
- `tests/unit/test-test-writer-dual-mode.bats` — currently asserts `model: opus` on line 52; update to assert `model:` is absent post-sweep.
- `tests/unit/test-change-type-partition.bats` — currently asserts model-routed dispatch on line 15; passes unchanged once the dispatcher's fallback path is exercised.
- `tests/unit/test-section-anchor-narrow-read.bats` — currently asserts `model: sonnet` on line 206; update to assert `model:` is absent post-sweep.
Worked example B — none plus grep-confirmed zero-match proof. A sweep task that removes a property no test currently asserts on cites a reproducible grep command the reviewer re-runs from the repo root:
- **Test expectations:**
- All 17 CD files have `${VAR}` references replaced with their resolved literals; behavior unchanged.
- `dependent_tests: none`
- `grep -rn -- '^model:' tests/` returns zero matches as of plan-authoring time; if a future test introduces an assertion on `model:` before this task lands, the reviewer's re-run will surface the new hit and demand the field be re-shaped to a path list.
A task is consumer-surface-touching when its description or files_in_scope indicates ANY of the following five trigger classes:
files_in_scope.files_in_scope.files_in_scope whose keys, anchors, or top-level identifiers are referenced by name from other files.files_in_scope.A task that only modifies the body of an existing callable, edits prose paragraphs without changing referenced anchor names, or fixes formatting is NOT consumer-surface-touching. The trigger fires on changes that other code or documents could plausibly be coupled to by name.
When the trigger fires, the plan-spec MUST include a cross_task_consumers: field with one of two shapes:
files_in_scope, each followed on the next line by a one-sentence disposition. The disposition vocabulary is exactly four values: no change (consumer keeps working unmodified), pass-through (consumer's behavior intentionally unchanged but the consumer file must be re-verified), co-edit (consumer file must be modified inside this same task), or break-and-fix-task (consumer file will be intentionally broken by this task and repaired in a named follow-up task — the follow-up task ID MUST be cited and MUST already exist in the plan).none followed on the next line by a reproducible search command demonstrating zero consumer references exist outside files_in_scope. Command shape is left to the author: grep, rg, git grep, a language-specific reference-finder (go vet, tsc --noEmit -p, rustc --emit=metadata, IDE-equivalent CLI), or any other reproducible zero-result probe. The reviewer re-runs the command and treats a non-zero hit count as a defect.Skipping the cross_task_consumers: field on a consumer-surface-touching task is a plan-spec defect, not a deferred-to-implementer concern. The Plan reviewer (agents/qrspi-plan-reviewer.md § Cross-task consumer surface detection) detects consumer-surface-touching tasks by the same trigger classes and emits a severity: high, change_type: correctness finding when the field is missing, malformed, claims none against a non-zero search hit, names an invalid disposition, or cites a break-and-fix-task follow-up task ID that does not exist in the plan.
Sweep + consumer composition. A task that satisfies BOTH the sweep-task trigger (see § Sweep Task Contract above) AND the consumer-surface trigger carries dependent_tests: AND cross_task_consumers: as separate fields. The two contracts ask different questions about different downstream surfaces (test files that assert on swept values vs. consumer files referencing the changed contract by name) and are not merged — the reviewer evaluates each clause independently and may emit findings against either, both, or neither.
Worked example C — public-symbol rename with three consumers (trigger fires). A task renames the public function check_codex_available to check_second_reviewer_available across the dispatcher script and one consumer skill, listing three consumer files outside files_in_scope with explicit dispositions:
- **Test expectations:**
- `scripts/dispatch-agent.sh` exports the renamed helper; `skills/using-qrspi/SKILL.md` calls the new name.
- `cross_task_consumers:`
- `skills/goals/SKILL.md` — references the old helper name in its inline availability probe; `co-edit` to rename the call site inside this task.
- `skills/implement/SKILL.md` — references the old helper name in the second-reviewer dispatch block; `co-edit` to rename the call site inside this task.
- `tests/unit/test-codex-host-vendor-matrix.bats` — asserts on the helper-name surface as documentation, not as an executable reference; `no change` because the test was rewritten in T07 to target the host×vendor matrix and no longer pins the helper name.
Worked example D — body-only bug fix (trigger does not fire). A task fixes an off-by-one error inside the body of an existing function in one file. No public-signature change, no rename, no schema change, no extension-point change. The cross_task_consumers: field is NOT required because the trigger does not fire — the change is body-only and no other file could be coupled to the bug-fix by name:
- **Test expectations:**
- `lib/pagination.go` `paginate()` returns the correct slice when `offset == len(items)`; existing public signature unchanged.
- (no `cross_task_consumers:` field — the trigger does not fire because this is a body-only bug fix with no public-signature, schema, or extension-point change.)
sizing_exception (post-split frontmatter) or Sizing exception bullet (in-plan) naming one of the closed exception set (split unless the exception is documented — see Task Sizing)+ joining feature names, or two distinct verbs joined by and (multi-feature bundle — split into per-handler tasks)config.md carries visual_fidelity_required: true and a task with visual_fidelity_check.ui_producing: true lacks a non-empty visual_fidelity_check.wireframe_refs list (refuses plan-review fan-out — see "Visual-fidelity hard-gate" below)reference_gate: true without a matching reference_artifact: field, or carries reference_artifact: without reference_gate: true (paired-field violation — Plan refuses to write the task spec; see Refuse-to-Write Contract above)ui: true and lift_source: <path> without a SPEC OVERRIDES SOURCE body section (paired-field violation — Plan refuses to write the task spec; see Refuse-to-Write Contract above)Before dispatching the plan-review reviewer fan-out (see "Review Round" above), the Plan orchestrator inspects config.md and the merged plan.md. The gate fires only when config.md carries visual_fidelity_required: true — runs with the flag unset, absent, or false are exempt entirely and the gate is a no-op. When the flag is on, the orchestrator walks every task spec in the merged plan.md and asserts that any task whose visual_fidelity_check.ui_producing field is true also carries a non-empty visual_fidelity_check.wireframe_refs list.
Failure mode. If any UI-producing task fails the assertion, the round halts before reviewer dispatch. The halt message names the offending task by its task number and surfaces the assertion that failed (visual_fidelity_check.wireframe_refs missing or empty) — the assertion fires for the absent-key, empty-list, and null-value sub-cases alike, and the diagnostic preserves that distinction rather than misreporting empty/null as "missing." No reviewers are dispatched until the plan author repopulates the block and the merged plan.md is re-checked. Multiple offending tasks are reported together in one halt so the author fixes them in a single pass.
Exemptions. Tasks that set ui_producing: false pass the gate regardless of whether wireframe_refs is populated. Whole-block omission — a task spec that carries no visual_fidelity_check block at all — is treated as ui_producing: false by design and passes the gate; the gate catches field-population errors inside a present block, not authoring slips that drop the whole block. The upstream invariant that catches "forgot to add the block on a UI task" lives elsewhere: the Split task file format template above seeds the block on every spec, and the per-task spec reviewer surfaces missing-block authoring errors against UI-producing task descriptions. Present-block parse error. A visual_fidelity_check block that is present but omits the ui_producing field entirely is a HARD parse error, not a falsy default: the gate halts, names the offending task by number, and surfaces the missing visual_fidelity_check.ui_producing field. Treating absence as false here would silently exempt UI-producing tasks whose author dropped a one-line boolean — exactly the failure mode the gate exists to catch. The gate's trigger condition is the visual_fidelity_required field in config.md (the same flag Goals writes at run creation and that the using-qrspi skill documents in its Config File section); the field is the single source of truth for whether the visual-fidelity binding chain is active on this run, and the gate consumes it by that exact name.
This is documented as a Plan-skill hard-gate — not a per-task review-time check — so the wireframe-binding contract is enforced once at plan-review time rather than re-checked downstream during Implement on every UI task.
| Rationalization | Reality |
|----------------|---------|
| "The implementation agent will figure out the details" | No. The plan is the contract. Vague specs produce wrong implementations. |
| "This task is similar to Task N, I'll just reference it" | Each task must be self-contained. The agent may read tasks out of order. |
| "Test expectations are implied by the description" | Write them explicitly. The Test skill uses them to generate acceptance tests. |
| "LOC estimates don't matter" | They signal scope. Unrealistic estimates mean the task is misunderstood. |
| "We can split this task during implementation" | Split now. The plan is where decomposition happens, not implementation. |
| "Splitting these features adds coordination overhead" | SWE-Bench Pro reports ~23% frontier-model success at the 107-LOC median patch size; tasks above the 200-LOC ceiling sit well past that empirical cliff. Coordination overhead is cheaper than the retry cost on a sub-50% pass rate. |
| "These features all live in the same file" | File overlap is not handler overlap. One handler per task even if multiple share a file — separate tasks can sequence edits inside one file via Dependencies. |
| "Schema setup naturally bundles, this is fine" | True only for the closed exception set: schema migration, CI scaffolding, reusable primitives. Mark sizing_exception: <reason> (post-split frontmatter) or Sizing exception bullet (in-plan) and explain in the Description. Do not use as a general escape hatch. |
| "Quick fix doesn't need a plan" | Quick fix mode still produces a plan — it's just a single-task plan. The plan ensures the fix is reviewed before implementation. |
Good task spec:
### Task 3: Rate limit middleware
- **Phase:** 1
- **Target files:** create `src/middleware/rate-limiter.ts`, modify `src/app.ts:34-40`
- **Dependencies:** Task 1 (Redis client), Task 2 (rate limit types)
- **LOC estimate:** ~60
- **Description:** Express middleware that checks the client's request count against the rate limit using the Redis client from Task 1. If exceeded, returns 429 with Retry-After header. If under limit, increments the counter and calls next().
- **Test expectations:**
- Returns 429 when client exceeds 100 requests/minute
- Returns Retry-After header with seconds until window resets
- Calls next() when client is under limit
- Increments Redis counter on each allowed request
- Extracts client ID from X-Forwarded-For header
- Returns 429 (not 500) when Redis is unreachable (fail closed)
- Handles missing X-Forwarded-For gracefully (use IP as fallback)
Bad task spec (vague, placeholders):
### Task 3: Rate limiting
- **Target files:** TBD
- **Dependencies:** none
- **LOC estimate:** ~200
- **Description:** Add rate limiting middleware. Similar to Task 2 but for the middleware layer.
- **Test expectations:**
- Rate limiting works correctly
- Edge cases are handled
The bad example has TBD files, no dependencies (but clearly needs the Redis client), unrealistic LOC, references "similar to Task 2", and test expectations that can't be verified ("works correctly", "are handled").
The three override-critical rules for Plan, restated at end:
No plan.md without all required artifacts approved. Full pipeline: goals + research + design + structure. Quick fix: goals + research. Plan refuses to run otherwise.
No placeholders in task specs. No "TBD", "TODO", "implement later", "similar to Task N", "add appropriate handling." Every task spec must be self-contained — an implementation agent reading only that task must have everything it needs.
One task = one observable behavior, ~100-LOC target / ≤200 LOC ceiling. Split before approving any task that exceeds the policy ceiling unless the task documents a sizing_exception (post-split frontmatter) or Sizing exception bullet (in-plan) naming one of the closed exception set: schema migration, CI scaffolding, reusable primitives. Multi-feature task titles (+ joining feature names, two distinct verbs joined by and) are the canary — they almost always mean multiple request handlers bundled into one task. SWE-Bench Pro reports ~23% frontier-model success at the 107-LOC median patch size; OpenAI AGENTS.md guidance targets ~100 lines; our 200-LOC ceiling sits at the lower bound of Cisco/SmartBear's code-review sweet spot with margin for QRSPI's enhanced scaffolding. See "Task Sizing" earlier in this skill for full rules including the floor.
Behavioral directives D1-D4 apply — see using-qrspi/SKILL.md → "BEHAVIORAL-DIRECTIVES".
documentation
Apply prompt-design rules when authoring or planning prompt-prose deliverables. Detects whether a deliverable IS prompt prose, and only then Reads the rules and applies R1-R7 before drafting. Preloaded by agent files that may author prompt prose.
testing
Apply prompt-design rules when reviewing prompt-prose subjects in a diff. Detects which files (or sub-blocks) are prompt prose, applies R1-R7 + cross-cutting principles + finding-type gate, and emits findings with proper change_type tagging. Preloaded by reviewer agents that may encounter prompt prose in their review subject.
development
Use when starting any conversation — establishes the QRSPI pipeline for agentic software development, requiring structured progression through Goals, Questions, Research, Design, Phasing, Structure, Plan, Parallelize, Implement, Integrate, Test, with Replan firing between phases
development
Use when implementation is complete (after Integrate in full pipeline, after Implement in quick fix) — runs acceptance testing against goals, routes failures through fix pipeline, handles phase completion and PR creation