/sdlc:task-review
Generated from solutions/ontological/skills/task-review/SKILL.md.
Description
Section titled “Description”Triage every unfinished task in docs/planning/tasks/: verify each is still relevant against the current codebase, check that the spec is complete enough to act on, update frontmatter (impact, complexity, last_reviewed, plus closed/done when code shows the work shipped), and produce a ranked recommendation of the next 1-2 tasks to tackle and why.
Allowed tools
Section titled “Allowed tools”ReadWriteEditBashGlobGrepAgentAskUserQuestion
Source
Section titled “Source”Usage:
/sdlc:task-review— triage every unfinished task./sdlc:task-review --since YYYY-MM-DD— only triage tasks last reviewed before that date, or whosecreated:falls after it./sdlc:task-review --tag <name>— only triage tasks whose frontmattertags:list contains<name>./sdlc:task-review --read-only— produce the ranked report without modifying any files.
Project context (don’t re-derive every run):
-
Task documents live in
docs/planning/tasks/. Active tasks useYYYY-MM-DD-<slug>.md; closed tasks may still use the olderNNNN-<slug>.md. Both shapes are valid. -
Full status/frontmatter schema in
docs/planning/tasks/README.md. Statuses considered “unfinished”: anything that does NOT start withclosed/. -
Frontmatter is validated by the sdlc plugin’s schema. Before the synthesis step (and any time you’ve just updated a batch of frontmatter), run the validator over the corpus:
${CLAUDE_PLUGIN_ROOT}cli/sdlc entities validate docs/planning/tasks/*.mdValidator failures are signal — usually a
closed-shape task missingresolution_date/resolution_commit, or a status that’s drifted from the canonical enum. Surface these in the synthesized report under “Schema violations” alongside the other gaps, and have the per-task sub-agent fix them as part of its frontmatter update. Schema lives at${CLAUDE_PLUGIN_ROOT}/entities/task/schema.ts. -
This skill keeps the backlog honest: it triages and re-ranks unfinished tasks. Starting a task is
/sdlc:task-work’s job. -
The authoritative definition of “implementation-ready” lives at
${CLAUDE_PLUGIN_ROOT}/entities/task/implementation-ready.md. Sub-agents apply that contract during the spec-completeness portion of their investigation (item 5 below). They surface gaps viadefinition_gap:but do NOT stampreadiness_verified_at:— that field is owned exclusively by/sdlc:task-ensure-ready(called immediately before work starts).
1. Survey
Section titled “1. Survey”ls docs/planning/tasks/*.mdand read frontmatter from each.- Build the unfinished list. Apply
--sinceand--tagfilters if provided. - If zero unfinished tasks, print
NO UNFINISHED TASKS — backlog is clean.and exit.
Print a one-line preview: Found <N> unfinished tasks across <statuses…>. Triaging in parallel.
2. Dispatch one sub-agent per task (parallel)
Section titled “2. Dispatch one sub-agent per task (parallel)”Spawn one sub-agent per unfinished task — each task gets its own dedicated investigator. Send all the Agent calls in a single message so they run concurrently. For large backlogs (>20 tasks), still spawn one agent per task.
Each sub-agent prompt must include:
-
Task file: the single absolute path to the task this agent owns.
-
Codebase root: the project working directory.
-
Mutation flag:
--read-onlyshould pass through as “do not edit files.” -
Full investigation contract (each agent does ALL of these for its one task):
-
Read the task body end-to-end. Not just frontmatter. Read every section: Goal, Today/Current state, Proposed, Approach, Files to touch, Acceptance criteria, Out of scope, Dependencies, Discovery context, etc. The agent should be able to explain in its own words what the task is asking for.
-
Verify every touchpoint row. In v3 (schema_version: 3), the task’s
## Todayand## Files to touchsections are| Location | ... |markdown tables using a five-form Location grammar (file, file+symbol, file+line, directory, glob). Shell out to the task noun’s resolver op, which decomposes each row and resolves its cited Location against the working tree in one call:${CLAUDE_PLUGIN_ROOT}cli/sdlc task resolve-touchpoints <task-file>The op emits a single JSON object
{ rows: [...] }. Each row carriessection(today/files_to_touch), the rawlocationcell, theparseddecomposition ({form, path, symbol, line},nullwhen the parser rejected the cell), the changekindit resolved AS (new/modify/delete;## Todayrows resolve asmodify), and the verdictresolved: true|falsewith a machinereasontoken (file-exists,file-missing,symbol-found,symbol-missing,directory-exists,glob-matches,glob-no-match,new,parse-error: …). The op decides existence under the five-form grammar so the agent does not re-spell the loop:form: file/form: linecheck file existence (line is a hint);form: symbolrequires file-exists AND the symbol token present;form: directorychecks the directory;form: globexpands to ≥1 match;kind: newrows fire no check.
Treat any
resolved: falserow as material drift: the cited Location no longer holds. Read thereasonand narrate what shifted in the decision below (the op reports existence only — drift narration is yours). Don’t cap the verification; the point is to confirm the task’s entire factual basis, not get a quick signal.Rows the parser rejected surface as
resolved: false, reason: "parse-error: …"(no filesystem probe) — relay the message. For tasks still on the v2 (or earlier) bulleted-shape, the resolver emits no rows for that section; confirm by runningtask parse-touchpoints <task-file>(it reports the sectionkind: bulleted-legacy), surface the gap, and recommend re-running/sdlc:entities-migrateto convert the shape — do NOT hand-fix the body.-
Cross-check against recent history.
git log --oneline -20andgit log --all --oneline | command grep <task-slug>to find any commits or branches that already touch this task’s surface. Look for:- Merged PRs that match the task slug.
- Commits whose message mentions the same symbol/file the task is rewriting.
- In-flight branches
task/<slug>that may already exist.
-
Read referenced related tasks. If the task’s frontmatter
related:or body contains[[other-task]]wikilinks or0NNN-foo.mdreferences, briefly check those target files’ current status — they may have moved the ground under this task. -
Evaluate spec completeness against the implementation-ready contract. Apply the contract from
${CLAUDE_PLUGIN_ROOT}/entities/task/implementation-ready.md. Read required body sections and frontmatter by eye. Decide the MECHANICAL disqualifiers with the same ops/sdlc:task-ensure-readyruns as its gate, so this skill’s gaps match the gate that runs before work starts:-
Touchpoint resolution — already covered by
resolve-touchpointsin item 2: everyresolved: falserow (includingparse-error: …rows and abulleted-legacysection) is a disqualifier. -
Placeholder-phrase disqualifiers — shell out to the task noun’s scanner op:
${CLAUDE_PLUGIN_ROOT}cli/sdlc task scan-placeholders <task-file>It emits a JSON array of matches (
{"section", "phrase", "line", "snippet"}); exit 0 with[]means none. Each match is a disqualifier — name the section and the matched phrase in the gap. The scanner already skips fenced code and inline-code spans, inspects only the required body sections, and flags unfilled<...>/empty table cells (e.g. an empty## Files to touchcell) under the phraseempty-table-cell. Its output needs no further filtering. -
Claim-resolver disqualifiers — shell out to the task noun’s check-claims op:
${CLAUDE_PLUGIN_ROOT}cli/sdlc task check-claims <task-file>It emits a JSON object keyed by resolver name; each value is a list of findings (
{"line", "severity", "message"}). Every resolver always appears as a key (empty array when it found nothing). Eachseverity: "disqualifier"finding is a gap — relay itsmessage(andline, if helpful).severity: "warning"findings are informational only. Today’s registry:paths(a cited path moved — basename matches an existing file under a different parent) andquantifiers(an AC asserts over a universal class without pinning the set).
-
Report each requirement and disqualifier as pass/fail in your return; a triggered op finding is a fail. Separately, note Dependencies completeness — Dependencies isn’t part of the contract but is relevant to ranking. If any contract check fails, the spec has a gap.
-
Decide one of (the 5-way):
- Already shipped — described “Today” state is gone and proposed code is in place. Set
status: closed/done. Addcompletion_note:citing real evidence — commit hash, PR number, or specific file change. Do not auto-close on inference: if the evidence isn’t unambiguous, surface to the orchestrator for confirmation rather than closing. - Obsoleted — the file/feature no longer exists or the surrounding architecture was
rewritten such that the task can never apply. Set
status: closed/obsoletedwithcompletion_note:explaining what changed and where the equivalent concern lives now (if anywhere). - Still relevant, accurate — task spec matches current code. Refresh
relevance_note:only if anything material shifted; otherwise leave it alone. - Still relevant, but spec drifted — paths/line numbers/symbol names moved, scope shrunk or
grew, dependencies changed status, etc. Update
relevance_note:with a precise diff of what shifted. Do NOT rewrite the body. - Spec incomplete — one or more of the completeness items is missing or thin. Add
definition_gap:listing what’s missing (e.g.definition_gap: missing AC and Files-to-touch). The task stays unfinished but is flagged as not-yet-workable.
- Already shipped — described “Today” state is gone and proposed code is in place. Set
-
Update frontmatter (skip in
--read-onlymode):impact: <high|medium|low>— high: addresses a bug, unlocks other work, removes a class of bugs; medium: meaningful quality improvement; low: nice-to-have / cosmetic / tiny scope. Overwrite any prior value if your fresh assessment disagrees.complexity: <small|medium|large>— small: <1 day; medium: 1-3 days; large: multi-day or multi-PR.last_reviewed: <today UTC>.definition_gap: <one paragraph>— set if and only if the implementation-ready contract from item 5 detected gaps. Be specific enough that the user knows what to fix; this is what/sdlc:task-definewill pick up later. Clear the field if a previously-flagged task now passes.- Do NOT set, clear, or otherwise touch
readiness_verified_at:— that field is owned exclusively by/sdlc:task-ensure-ready. - Body content is never modified.
-
Note dependencies and unblock relationships for the synthesis step. Be explicit: “this task must land before X because
”, or “this task is now unblocked because Y shipped”.
-
-
Return format (per agent, structured for easy aggregation):
Task: <filename>Status: <new status if changed, else unchanged>Impact: <high|medium|low>Complexity: <small|medium|large>Decision: <shipped|obsoleted|relevant-accurate|relevant-drifted|incomplete>Definition gap: <list, or none>Spec completeness: <which sections present/missing>Key findings: <2-4 bullets, including any code citations that informed the decision>Dependencies: <list>Confidence in decision: <high|medium|low>; if not high, what would clarify itKeep each agent’s report under 300 words; favor structure over prose.
Each agent has narrow scope (one task) — go deep on that scope rather than skim.
3. Synthesize ranking
Section titled “3. Synthesize ranking”When all sub-agents return, build a single ranked report:
Tier 1 — high-impact, do soon
Section titled “Tier 1 — high-impact, do soon”High-impact tasks (bug fixes, unblockers) that are also open/ready / in-progress and
well-defined. These are the actionable picks.
Tier 2 — quick wins to bundle
Section titled “Tier 2 — quick wins to bundle”Small-complexity items that are worth picking up alongside the Tier 1 work, especially if they touch overlapping files.
Tier 3 — defer
Section titled “Tier 3 — defer”Medium/low impact OR blocked by another task OR spec still incomplete.
Tier 4 — rewrite or drop
Section titled “Tier 4 — rewrite or drop”Stubs, abandoned drafts, or things now-obsolete that should be deleted or rewritten. Recommend a concrete action for each.
Newly closed during this run
Section titled “Newly closed during this run”List every task whose status was changed to closed/done or closed/obsoleted by sub-agents, with
the one-line completion_note:.
Definition gaps
Section titled “Definition gaps”List every task that picked up a definition_gap: field — these are tasks the user should flesh out
before /sdlc:task-work can pick them up. Suggest /sdlc:task-define <basename> as the interactive
way to resolve each.
Final recommendation
Section titled “Final recommendation”1-2 specific picks for the next session. State the why in terms of dependency ordering (does it unblock others?), risk class (does it close a bug?), and effort (small/medium/large). If there are no good Tier-1 picks, say so plainly rather than padding.
4. Optional: ask before mutating closures
Section titled “4. Optional: ask before mutating closures”If sub-agents proposed marking a task closed/done based on inference (no obvious commit hash, no
merged PR reference), surface those to the user via AskUserQuestion before the close is finalised.
Auto-close only when the evidence is unambiguous (e.g. described file deleted upstream, or commit
message explicitly names the task).
5. Render the report, then summarize
Section titled “5. Render the report, then summarize”First the durable artifact, then the conversation:
-
Assemble the report payload per the contract in
${CLAUDE_PLUGIN_ROOT}lib/model/entities/task/reports/review/schema.ts(meta header, filters, one row per reviewed task with tier/decision/findings, newly closed, schema violations, final recommendation). Read the schema — its.describe()annotations are the authoring doc; counts and tallies are derived by the template, so the payload carries none. Write the JSON to a temp file, then follow the render recipe in${CLAUDE_PLUGIN_ROOT}conventions/skill-reports.md:${CLAUDE_PLUGIN_ROOT}cli/sdlc report render task-review <payload.json>On a contract violation the op exits non-zero with the Zod issues — fix the payload and re-run; never hand-write the HTML.
-
Link, then talk. Print a clickable
file://link to the rendered HTML report (plus the JSON sidecar path), then print the synthesized ranking inline.
Stop here. Do not start any task.
- One agent per task: always. Even for a 3-task backlog, spawn 3 agents, each going deep on its one task. Do NOT batch multiple tasks into one agent.
- Send all agents in one message: dispatch every Agent call in a single response so they run in parallel.
- No
lib/docsrewriting: edit only frontmatter and synthesis output; never edit code or rewrite task bodies. - Definition gaps are signal, not blockers: a task with
definition_gap:is still in the backlog; it just isn’t workable yet. Surface them so the user can fix them, but don’t mark them closed. - Don’t invent dates: when summarising “shipped” tasks, reference real commits / PRs found via
git log. If you can’t find evidence, proposeclosed/doneonly after asking the user. - Schema-contracted reports. See
${CLAUDE_PLUGIN_ROOT}conventions/skill-reports.md— this skill’s kind slug istask-review.--read-onlysuppresses frontmatter edits, NOT the report:.sdlc/reports/is gitignored runtime output, not a project mutation. - When in doubt about a closure, ask via AskUserQuestion — mis-closing a task is worse than one extra question.