From prd2impl
Task generation with dependency analysis — convert gap analysis into a structured task list with types (Green/Yellow/Red), dependencies, and deliverables. Use when the user says 'generate tasks', 'break down into tasks', 'create task list', or after /gap-scan.
How this skill is triggered — by the user, by Claude, or both
Slash command
/prd2impl:skill-3-task-genThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<SUBAGENT-STOP>
Convert gap analysis results into a structured task list with dependency graph, color classification, and verification criteria.
/task-gen/gap-scan has produced gap-analysis.yaml{plans_dir}/*-gap-analysis.yaml (output from skill-2 or skill-0) — see §Step 1.5 B2 Degradation{plans_dir}/*-prd-structure.yaml (output from skill-1 or skill-0) — see §Step 1.5 B2 Degradation{plans_dir}/*-task-hints.yaml (output from skill-0 only — see §Step 2.5)docs/plans/project.yaml (team configuration; always at project root){plans_dir}/tasks.yaml (for incremental updates — see docs/superpowers/specs/2026-04-20-plans-dir-scoping-design.md §8 Limitation 6 for status)Path resolution: Before constructing any output path, resolve
{plans_dir}perlib/plans-dir-resolver.md. Alldocs/plans/references below (exceptdocs/plans/project.yaml, which stays at repo root) are relative to that resolved directory.
gap-analysis.yaml and prd-structure.yaml. Do NOT error on miss — if either file is absent, remember which is missing and proceed to §Step 1.5 to evaluate B2 degradation before emitting any error.task-hints.yaml — if found, load it (see §Step 2.5)gap_analysis was synthesized in §Step 1.5)skill-3 can operate without prd-structure.yaml and/or gap-analysis.yaml provided task-hints.yaml is present and has a non-empty implementation_steps list. This unblocks the design-spec workflow where no gap-scan has run.
At the end of Step 1 (Load Gap Analysis), check what was loaded:
gap-analysis.yaml was NOT found AND task-hints.yaml WAS found: synthesize gap_analysis = { gaps: [] } in memory.prd-structure.yaml was NOT found AND task-hints.yaml WAS found: synthesize a skeleton prd_structure in memory (see §Skeleton synthesis below).task-hints.yaml was NOT found OR implementation_steps is empty: do NOT synthesize — fall through to the original hard-error behavior of Step 1.The synthesized structures are never written to disk — they exist only for the duration of this /task-gen invocation.
prd_structure:
source_type: "synthesized-from-task-hints"
source_role: "design-spec"
modules:
# One module per implementation_step entry
- id: MOD-01
name: "<step.description truncated to 60 chars>"
description: "<step.description (full)>"
prd_sections: []
sub_modules:
# One sub_module per file in step.touches_files
- id: MOD-01a
name: "<file basename>"
description: "<file path>"
user_stories: []
nfrs: []
constraints: []
external_deps: []
Sequential numbering: MOD-01, MOD-02, ... matching the step numbers. Sub-module suffix: MOD-01a, MOD-01b, ... per file within a step.
Every task emitted under B2 degradation MUST include:
tasks:
- id: T<phase><line>.<seq>
...
traceability: task-hints-only # NEW field — absent in normal mode
synthesized_module_id: MOD-NN # NEW field — links to skeleton module
Downstream skills (contract-check, retro) key off traceability: task-hints-only to skip checks that need real user_stories / constraints / external_deps.
Before writing tasks.yaml, print:
─────────────────────────────────────────────────────
B2 degradation mode active
─────────────────────────────────────────────────────
Missing: {list of absent required files}
Synthesized {N} skeleton modules (MOD-01..MOD-{N}) from implementation_steps.
user_stories / nfrs / constraints / external_deps are empty — downstream
skills (contract-check, retro) will skip checks that depend on these fields.
Re-run /ingest-docs on a richer source document to upgrade.
─────────────────────────────────────────────────────
/ingest-docs afterward produces real files; this skeleton was only scaffolding for this /task-gen invocation.For each gap, generate one or more tasks:
Task ID Convention: T{Phase}{Line}.{Seq}
project.yaml team config (e.g. A, front, infra), or S for shared/cross-lineClassification Rules:
Auto color-promotion (0.4.0+): After applying the standard rules
above, run the auto-promote check. A task originally typed green is
promoted to yellow (and auto_promoted: true is set on the task)
when ANY of:
affects_files / deliverables[*].path glob matches any of:
**/auth*/**, **/permission*/**, **/login*, **/token*, **/credential***/*contract*, **/*protocol*, **/*schema* (excluding test files)must_call_unchanged list is non-emptymeta.connector_seam: true (already set by R15 / 0.3.1 connector-seam rule)env_var.class: A (security boundary)When auto-promotion fires, set type: yellow and auto_promoted: true
on the generated task. Yellow handling proceeds as normal (review,
preflight, contract re-read).
Rationale: M3 retro batch-2 §🟢 finding "some Green tasks have hidden security surface that should go through review." The 14/14 reviewer-caught Critical bug rate in M3 confirms this is high ROI.
Task Structure:
tasks:
- id: T1A.1
name: "Mode/Gate minimal implementation"
description: "Implement state machine for conversation modes and gate transitions"
line: backend # Line identifier from project.yaml, or 'shared'
type: green # green | yellow | red
phase: P1
module: MOD-01
gap_ref: GAP-003 # Links to gap-analysis
story_refs: [US-005, US-006] # Links to PRD stories
depends_on: [T0.4]
blocked_by: [] # External blockers (not task deps)
deliverables:
- path: "autoservice/conversation_engine/mode_gate.py"
type: code # code | test | doc | config
- path: "tests/unit/test_mode_gate.py"
type: test
may_touch: # Files this task might modify beyond deliverables
- "autoservice/conversation_engine/__init__.py" # Add import
- "autoservice/config.yaml" # Add config entry
verification: "pytest tests/unit/test_mode_gate.py — all green"
estimated_effort: small # small (<2h) | medium (2-8h) | large (>8h)
status: pending
owner: null
artifacts: []
Gate: Skip this entire step if no task-hints.yaml was found in Step 1. When absent, task generation is byte-identical to before this change was made.
When task-hints.yaml is present, FIRST check for the plan-passthrough short-circuit (Step 2.5.0). If it fires, the Behavior 1/2/3 logic below does NOT apply. Otherwise, apply the three behaviors that override defaults in Step 2.
Triggers when: task_hints.source_type == "ingested" AND task_hints.tasks[] is present and non-empty AND every entry in tasks[] carries a source_plan_path.
When triggered, use the plan-file mapping below INSTEAD of Behaviors 1/2/3 below. The legacy file_changes / implementation_steps logic remains the default for design-spec ingest and hand-written plans without the writing-plans header.
Group task_hints.tasks[] by source_plan_path. For each unique plan-file group, emit exactly one prd2impl task to tasks.yaml:
- id: "{see ID rule}"
name: "{see name rule}"
type: green # default; see type-inference rule
phase: "{see phase rule}"
module: "" # plan itself is the module
source_plan_path: "{unique plan path for this group}"
source_plan_task_count: {count of entries in this group}
source_plan_step_count: {sum of len(steps) across the group}
deliverables:
# aggregated across all plan-tasks in the group, de-duplicated by path
- path: "{path}"
change_type: "create | modify"
verification:
- "All checkbox steps in {source_plan_path} are checked (executing-plans tick state)"
- "git diff vs base branch matches the plan's aggregated File Structure (see skill-10 Step 2.5)"
depends_on: [] # see dependency-inference rule
Note: prd2impl tasks emitted via Step 2.5.0 do NOT carry source_plan_anchor (no anchor — the whole plan is the unit). The per-plan-task anchors, files, and step counts stay in task-hints.yaml and are read directly by skill-9 / skill-10.
For each unique source_plan_path:
files.create across all tasks[] entries → change_type: create.files.modify across all entries → change_type: modify.files.test and merge into create if the test path is a new file under tests/, else into modify.path. If a file appears in both create and modify across different plan-tasks, prefer create.Match the plan filename pattern \d{4}-\d{2}-\d{2}-(?:[a-z0-9-]+-)?p(\d+)([a-z]?)-.+\.md to extract the plan-letter:
*-p1-*.md → T1*-p2-*.md → T2*-p4a-*.md → T4A*-p4b-*.md → T4B*-p6a-*.md → T6AIf the filename does NOT match the p\d+[a-z]? pattern, fall back to TP{1-based ordinal of plan in input list} (e.g. TP3 for the 3rd plan).
Use the plan's H1 with the trailing Implementation Plan stripped. Fall back to the filename stem (with date prefix stripped) if the H1 is missing or generic.
If project.yaml defines phases[], match the plan-letter to a phase (e.g. p1 → phase P1). If no match, set phase: "ingested".
Default: type: green. The granularity is now plan-level — most plans bundle a mix of green/yellow/red work. Default to green and let the user re-classify in tasks.yaml if needed. Exception: if the plan filename or H1 mentions design, policy, decision, architecture, default to red (these plans typically front-load design decisions).
For each emitted task, order by plan-letter (p1 < p2 < p3 < p4a < p4b < p5 < p6a < p6b — natural ordering by digit then letter suffix). Set depends_on: ["T{prev-plan-letter}"] if a prev plan was ingested in the same call. Sequential chaining is the safe default — the user edits tasks.yaml afterward for non-linear deps.
Print a hint at end of generation:
Cross-plan dependencies inferred sequentially (T2 depends on T1, T3 on T2, ...).
Review tasks.yaml depends_on if your plans have non-linear deps.
gap-analysis.yaml cross-referencing (writing-plans format does not carry GAP-NNN refs)The legacy file_changes / implementation_steps / non_goals logic is not applicable: writing-plans format doesn't use those fields. Continue to Step 2.6 (house conventions) after this step.
Branching note: the three Behaviors below run ONLY when Step 2.5.0 did NOT fire (i.e.,
task_hintscarries legacy file_changes / implementation_steps but notasks[]). For plan-passthrough hints, Step 2.5.0 fully replaces them.
Instead of inferring deliverable paths from gap descriptions:
task_hints.file_changes entry, create a deliverable.file_changes by their related_gap_refs[0] (primary gap ref). All file_changes sharing the same primary gap → one task with multiple deliverables.file_change has additional related_gap_refs beyond the first, store those as cross_references on the task (do not create duplicate deliverables).file_changes with empty related_gap_refs → assign to a shared catch-all task; emit warning "orphan file_change assigned to shared task".Instead of (or in addition to) dependency inference in Step 3:
task_hints.implementation_steps entry:
touches_files (matched via deliverables from Behavior 1).step.depends_on_steps reference → find the tasks that own those step's files → add those tasks to depends_on.depends_on_gaps still applies.Before emitting any task, check each task.deliverables[*].path against task_hints.non_goals:
"task excluded per non_goal: '{non_goal}' matches '{path}'"tasks.yaml; they are listed at the bottom of the summary.Before emitting each task, read {plans_dir}/conventions.md (if
exists, written by skill-2-gap-scan Step 3.5). For each task whose
affects_files glob matches a file referenced by the conventions
cheat-sheet, inline the relevant conventions into the task's
context_block field:
- id: T-EXAMPLE.2
...
context_block: |
Project conventions for files touched here:
- IDs: secrets.token_urlsafe(36) (see autoservice/customer_manager.py:42)
- Timestamps: ISO 8601 (`datetime.utcnow().isoformat()`)
- Logger: `logger = logging.getLogger(__name__)` per module
- MCP servers: hook into cc_pool.py:691 auto-inject — DO NOT duplicate
Subagents in skill-8-batch-dispatch see this in their dispatch
prompt, eliminating the "reinvented ID format" and "reinvented MCP
bootstrap" failure modes.
When conventions.md is absent (skill-2 not run, or skill-2 missing
Step 3.5 from older 0.3.x install), skip silently — task generation
proceeds without the inlined block.
Generate dependency graph:
dependency_graph:
# Adjacency list: task → [tasks that depend on it]
T0.1: [T0.3, T0.4, T1A.4]
T0.2: [T0.3, T0.5, T0.6]
T0.4: [T0.5, T1A.1, T1A.2, T1A.3]
# ...
critical_path: [T0.1, T0.4, T1A.1, T2A.1, T3A.7, T4A.4, T5A.1]
critical_path_length: 7 # Longest chain
For each non-Red task generated in the previous step, derive test_requirements
from the linked acceptance criteria.
Input sources:
gap_ref → gap-analysis.yaml → gaps[].acceptance_criteria or gaps[].expected_behaviorstory_refs → prd-structure.yaml → user_stories[].acceptance_criteriamust_call_unchanged → contract symbols (for integration layer)Derivation logic:
For each task:
1. If task.type == "red":
- test_requirements: {} (empty, no test obligation)
- completion_criteria: { tests_pass_required: false, review_required: true, artifacts_required: [review_checklist] }
- SKIP remaining steps for this task
2. Resolve acceptance criteria:
a. For each story_ref in task.story_refs:
- Find user_story in prd-structure.yaml where id matches
- Extract acceptance_criteria list
b. If task.gap_ref:
- Find gap in gap-analysis.yaml where id matches
- Extract expected_behavior or acceptance_criteria
c. If neither source has criteria → test_requirements left empty, mark task with warning:
"⚠️ No acceptance criteria found for {task.id} — test_requirements will be stub.
Add acceptance criteria to prd-structure.yaml or gap-analysis.yaml and re-run /task-gen."
3. Generate unit test requirements:
For each acceptance criterion:
- description: Convert criterion into a testable assertion
- covers: [story_id, ac_id]
- expected_count: 1 (default); increase for multi-branch criteria
- status: active
- status_reason: null
- status_decided_by: auto
4. Generate integration test requirements:
For each contract_symbol in task.must_call_unchanged:
- description: "Verify {symbol} contract is not broken by this task"
- covers: [task.gap_ref]
- contract_symbols: [symbol]
- status: active
If task.meta.connector_seam == true:
- Generate integration test for producer→consumer data flow
5. Generate e2e test requirements:
- Single-module task with no cross-task dependencies → e2e: []
- Entry/exit point of dependency graph → mark for skill-4 E2E inclusion
6. Set completion_criteria defaults by task type:
Green: { tests_pass_required: true, review_required: false, artifacts_required: [eval_doc, test_plan, test_diff, e2e_report] }
Yellow: { tests_pass_required: true, review_required: true, artifacts_required: [test_plan, test_diff, e2e_report, review_checklist] }
Red: { tests_pass_required: false, review_required: true, artifacts_required: [review_checklist] }
7. Write test_requirements and completion_criteria to the task entry in tasks.yaml
Degradation handling:
If prd-structure.yaml or gap-analysis.yaml is unavailable or has no acceptance_criteria:
⚠️ TEST REQUIREMENTS DEGRADED — acceptance criteria source missing.
{missing_source} not found or has no acceptance_criteria.
test_requirements will be generated as stub (empty) for all tasks.
Tasks will fall back to legacy verification field for gating.
To restore: ensure prd-structure.yaml and gap-analysis.yaml have
acceptance_criteria fields, then re-run /task-gen.
Record in capability-profile.yaml:
degraded_paths:
- skill: skill-3
capability: test_requirements_generation
fallback: stub_test_requirements
reason: "{missing_source} not found or has no acceptance_criteria"
Group tasks into phases/milestones based on:
phases:
- id: P0
name: "Contracts & Skeleton"
milestone: M0
tasks: [T0.1, T0.2, T0.3, T0.4, T0.5, T0.6]
gate: "All contract files frozen, skeleton code compiles"
- id: P1
name: "Core Features"
milestone: M1
tasks: [T1A.1, T1A.2, ..., T1B.1, T1B.2, ...]
gate: "End-to-end conversation flow works"
If project.yaml defines team lines, assign tasks:
shared with designated driverGenerate summary:
summary:
total_tasks: 75
by_type:
green: 48 (64%)
yellow: 18 (24%)
red: 9 (12%)
by_line:
# Dynamic — one entry per line from project.yaml
backend: 43
frontend: 29
shared: 3
by_phase:
P0: 6
P1: 17
P2: 12
# ...
critical_path_length: 7
estimated_duration: "3 days (with 2 parallel lines)"
warnings:
- "T3A.4 (Red) blocks 3 downstream tasks — start early"
- "P5 has 8 tasks depending on external zchat API (DEP-01)"
- "Line 'backend' has 48% more tasks than 'frontend' — consider rebalancing"
{plans_dir}/{date}-tasks.yaml (structured data){plans_dir}/{date}-tasks.md (human-readable table format)STOP here. Present task list and wait for user review.
Task generation complete. {N} tasks across {P} phases. Type split: {G} Green / {Y} Yellow / {R} Red Critical path: {CP} tasks deep
Review
{plans_dir}/{date}-tasks.yamland confirm:
- Task granularity — any too large (>8h) or too small (<30min)?
- Color classification — any Green that should be Yellow/Red?
- Dependencies — any missing or incorrect links?
- Phase grouping — any tasks in the wrong phase?
When ready, see the chain-hint footer below for next steps.
When task decomposition splits a producer/consumer pair across separate tasks (e.g. one task implements a data emitter, a sibling task implements the consumer that filters/routes/displays it), the decomposition leaves a connector seam: each unit-tests cleanly in isolation, but a missing field or contract mismatch at the seam makes the whole pipeline silently inert in production.
Detect connector seams by these signals during task generation:
module but cover different stages of a data flow (one writes a field, another reads it)gap_ref says "evaluate per-tenant" / "filter by X" / "route to Y" while a sibling task says "produce records of type X" — the producer must populate the field the consumer keys ondeliverables produce records consumed by another task's deliverables (cross-task data dependency, not just file-import dependency)For every detected seam, append an integration task:
- id: T<phase><line>.<seq>
name: "Integration: {producer task} → {consumer task} pipeline"
type: green
module: <shared module>
description: "End-to-end test that exercises the full pipeline from {producer} through {consumer}, asserting the observable behavior at the consumer end (not just that each unit's tests pass)."
depends_on: [<producer task id>, <consumer task id>]
deliverables:
- path: "tests/integration/test_<feature>_pipeline.py"
type: test
verification: "Test fails if producer omits the connector field OR consumer ignores it OR the wire format drifts."
estimated_effort: small # usually 30-60min
meta:
connector_seam: true
connects: [<producer task id>, <consumer task id>]
M3 retro evidence (T2S.5 AlertEngine): producer task built FiredAlert records, consumer task added per-tenant push filter. Both tasks' unit tests passed. The producer never set tenant_id on the record — so the consumer's filter always short-circuited and the feature was dead in production despite 100% green tests. Reviewer caught it; integration test would have caught it earlier and cheaper.
Add at most one integration task per connector seam. Do not generate integration tasks for trivial seams where the producer and consumer share a single file and the unit tests already exercise the full path. The goal is catching cross-task data drift, not test inflation.
───────────────────────────────────────────────────── ⬆ /task-gen complete ─────────────────────────────────────────────────────
📋 Next: /plan-schedule — create batches and milestones /next-task — start working immediately ─────────────────────────────────────────────────────
npx claudepluginhub ezagent42/prd2impl --plugin prd2implCreates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.