osdlc

task-review

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.

osdlc 3 Updated 2w ago

Resources

1
GitHub

Install

npx skillscat add osdlc/osdlc/task-review

Install via the SkillsCat registry.

SKILL.md

$sdlc:task-review

Usage:

  • $sdlc:task-review — triage every unfinished task.
  • $sdlc:task-review --since YYYY-MM-DD — only triage tasks last reviewed before that date, or
    whose created: falls after it.
  • $sdlc:task-review --tag <name> — only triage tasks whose frontmatter tags: 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 use YYYY-MM-DD-<slug>.md; closed
    tasks may still use the older NNNN-<slug>.md. Both shapes are valid.

  • Full state/frontmatter schema in docs/planning/tasks/README.md. States considered
    "unfinished": anything that does NOT start with closed/.

  • 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:

    scripts/sdlc entities validate docs/planning/tasks/*.md

    Validator failures are signal — usually a closed-shape task missing
    resolution_date/resolution_commit, or a state 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}/lib/model/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}/lib/model/entities/task/implementation-ready.md. Sub-agents apply that
    contract during the spec-completeness portion of their investigation (item 5 below). They surface
    gaps via definition_gap: but do NOT stamp readiness_verified_at: — that field is owned
    exclusively by $sdlc:task-ensure-ready (called immediately before work starts).

1. Survey

  1. ls docs/planning/tasks/*.md and read frontmatter from each.
  2. Build the unfinished list. Apply --since and --tag filters if provided.
  3. If zero unfinished tasks, print NO UNFINISHED TASKS — backlog is clean. and exit.

Print a one-line preview: Found <N> unfinished tasks across <states…>. Triaging in parallel.

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-only should pass through as "do not edit files."

  • Full investigation contract (each agent does ALL of these for its one task):

    1. Read the task body end-to-end. Not just frontmatter. Read every section: Goal,
      Today/Current state, Proposed, Approach, Areas, 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.

    2. Sanity-check ## Today and ## Areas, but do not gate on either resolving.
      As of v7, ## Today is free-form prose (no table shape, no path-existence
      check) and ## Areas is an advisory list of packages/directories/modules
      the task expects to touch — an Area never has to name an exact existing
      path. Neither section is resolved against the working tree by any op.
      Read them by eye: does the described current state still match reality,
      and do the named areas still make sense given what you find in item 3
      (recent history) and item 4 (related tasks)? If something has clearly
      moved or no longer exists, that's spec drift (item 6's "still relevant,
      but spec drifted" outcome) — not a readiness disqualifier, since Areas
      was never a resolution gate. Stale path CITATIONS anywhere in the body
      (backticked, extension-bearing tokens) are still caught mechanically by
      the paths claim resolver in item 5.

    Don't cap the verification; the point is to confirm the task's entire
    factual basis
    , not get a quick signal.

    1. Cross-check against recent history. git log --oneline -20 and
      git 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.
    2. Read referenced related tasks. If the task's frontmatter related: or body contains
      [[other-task]] wikilinks or 0NNN-foo.md references, briefly check those target files'
      current state — they may have moved the ground under this task.

    3. Evaluate spec completeness against the implementation-ready contract. Apply the contract
      from ${CLAUDE_PLUGIN_ROOT}/lib/model/entities/task/implementation-ready.md. Read required
      body sections and frontmatter by eye. Decide the MECHANICAL disqualifiers with the same ops
      $sdlc:task-ensure-ready runs as its gate, so this skill's gaps match the gate that runs
      before work starts:

      • Touchpoint resolution — N/A since v7: ## Today and ## Areas are no longer resolved
        against the working tree (item 2 is a by-eye sanity check, not a disqualifier source).

      • Placeholder-phrase disqualifiers — shell out to the task noun's scanner op:

        scripts/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 ## Areas cell) under the phrase
        empty-table-cell. Its output needs no further filtering.

      • Claim-resolver disqualifiers — shell out to the task noun's check-claims op:

        scripts/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). Each severity: "disqualifier" finding is a gap — relay its message
        (and line, 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) and quantifiers (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.

    1. Decide one of (the 5-way):

      • Already shipped — described "Today" state is gone and proposed code is in place. Set
        state: closed/done. Add completion_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 state: closed/obsoleted with
        completion_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 state, 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 Areas). The task stays unfinished but is flagged as
        not-yet-workable.
    2. Update frontmatter (skip in --read-only mode):

      • 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-define will 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.
    3. 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>
    State: <new state 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 it

    Keep 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

When all sub-agents return, build a single ranked report:

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

Small-complexity items that are worth picking up alongside the Tier 1 work, especially if they touch
overlapping files.

Tier 3 — defer

Medium/low impact OR blocked by another task OR spec still incomplete.

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

List every task whose state was changed to closed/done or closed/obsoleted by sub-agents, with
the one-line completion_note:.

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

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

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

First the durable artifact, then the conversation:

  1. 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:

    scripts/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.

  2. 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.

Notes

  • 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/docs rewriting: 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, propose closed/done only after asking the user.
  • Schema-contracted reports. See ${CLAUDE_PLUGIN_ROOT}/conventions/skill-reports.md — this
    skill's kind slug is task-review. --read-only suppresses 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.