Skip to content

/sdlc:review-todos

Generated from solutions/ontological/skills/review-todos/SKILL.md.

Scan the codebase for TODO / FIXME / HACK comments, judge each one’s worth in context, and ask the user what to do per item: promote to a task (immediate work), capture as a backlog item (defer triage), edit the comment in place, or skip. Promotion to a task calls sdlc task create and commits on main; promotion to a backlog item calls sdlc backlog create, which lands it on the rolling backlog-capture PR.

  • Read
  • Edit
  • Bash
  • AskUserQuestion

Usage:

  • /sdlc:review-todos — scan the whole tracked codebase.
  • /sdlc:review-todos <path> — scan a single file or subtree (path relative to repo root, or absolute).

Project context (don’t re-derive every run):

  • Tasks live at docs/planning/tasks/<id>-<slug>.md (id minted by task create). Backlog items at docs/planning/backlog/<id>-<slug>.md.
  • Scanning is delegated to sdlc project scan todos. Task creation is delegated to sdlc task create; backlog capture is delegated to sdlc backlog create (the rolling-PR tail). Don’t reimplement what they own.
  • Validation: sdlc entities validate (the backlog tail validates its own output, so explicit validation only applies to the task-creation branch).
  • This skill commits directly on main, one commit per decision that produces an artifact — except backlog capture, which sdlc backlog create lands on the rolling backlog-capture PR (and any source-TODO annotation that accompanies it still commits on main). It is lightweight intake: no worktree.
  • The TODO comment itself stays in the source file by default. Optionally annotate it with a wikilink to the new artifact so the connection is discoverable from the code.

Run the scanner:

${CLAUDE_PLUGIN_ROOT}cli/sdlc project scan todos --json [--path <path>]

Under --json the op prints {hits: [...]} to stdout. Each hit has fields path, line, marker, text (the verbatim matched source line), and stripped (the comment content after the marker). For the hit schema and the flags it accepts (--path, --markers, --include-planning), see sdlc project scan todos --help. How this skill consumes that output:

  • Use each hit’s op-provided stripped content for the derived slug and headline — do not re-derive it from text. The body seed still quotes the verbatim source line from text, so a reader sees the exact comment in context.
  • Pass --include-planning only if the user explicitly wants to triage the SDLC system’s own TODOs.

If a path argument was given to the skill, forward it via --path. Parse the JSON output; if the hits array is empty, exit NO TODOs FOUND.

Otherwise, report a one-line summary at the start: N TODOs across M files. Then enter the per-item loop in the order the script produced them.

For each hit:

  1. Read context. Use Read on the file with an offset that captures ~10 lines before and ~20 lines after the TODO line. The point is to understand what the comment is actually pointing at — the function it lives in, what’s incomplete, whether it’s a stub or a future enhancement.

  2. Evaluate. Form a one- to two-sentence judgment covering:

    • What the TODO is asking for (paraphrased — don’t just echo the comment).
    • Whether it looks trivial (a few lines, no design questions), scoped (a real task — clear intent, bounded surface), vague (intent unclear or speculative — needs more thought before any work), or stale (the surrounding code looks like it already addressed this, or the referenced concern no longer applies).
    • A recommended disposition: task, backlog, edit-in-place, or skip.

    Present the file path with line number (path/to/file.py:142), the raw TODO line, your evaluation, and your recommendation. Keep this block under 8 lines.

  3. Ask via AskUserQuestion. Header Disposition. The first option should mirror your recommendation and be labelled (Recommended). Always offer all four:

    • Create task — promote to an immediate work item. Use when the TODO is concrete and worth doing soon. Calls sdlc task create.
    • Create backlog item — capture for later triage. Use when worth remembering but not urgent, or when intent needs refining before it can be a task. Calls sdlc backlog create.
    • Edit in place — open a brief follow-up to rewrite or remove the comment (e.g. it’s stale, or it should be reworded to be more precise). Useful when the right answer is just “this comment shouldn’t exist” or “the comment is wrong about why.”
    • Skip — leave the TODO and source file untouched, continue to next item.
  4. Execute the choice (sections 3–6). Then continue the loop.

The user can interrupt at any time. Committed decisions stay. Unprocessed TODOs simply resurface on the next run.

  1. Preview the would-be slug and id with the read-only task preview-id op, passing the hit’s stripped content:

    ${CLAUDE_PLUGIN_ROOT}cli/sdlc task preview-id "<stripped>" --output json

    It derives the capped slug for you (the shared substrate derivation — don’t re-derive it) and reports the would-be id, plus whether an identical (exists / exact_match) or similar (similar[]) task already exists. The marker form is PREVIEW-ID task slug=<slug> id=<id> exists=<bool> similar=<n>; on empty/bad input it exits 1 (INVALID_INPUT) — surface that and skip the item.

    Dedup gate. If exists is true, or similar[] is non-empty, a matching task may already exist — ask via AskUserQuestion (Disposition header) whether to proceed anyway, point the source annotation at the existing task’s id instead, or skip. Only continue creating when the user confirms there’s no duplicate.

  2. Ask for a headline in plain text: “One-line headline for the task? (default: <derived from TODO>)”. The default is the hit’s stripped content, capitalized. Accept the default if the user replies empty / “y” / “ok”.

  3. Single AskUserQuestion for triage (3 questions): Status (planning/draft / planning/proposed / open/ready), Impact (high / medium / low), Complexity (small / medium / large). Recommend planning/draft for first capture unless you specifically judged the TODO as ready-to-pick-up.

  4. Create the task. Omit the positional slug — create derives the same capped slug from --headline (the slug preview-id showed you), so there’s nothing to hand off:

    ${CLAUDE_PLUGIN_ROOT}cli/sdlc task create \
    --headline "<headline>" \
    --status <status> \
    --impact <impact> \
    --complexity <complexity>

    Capture the printed absolute path. The basename is <id>-<slug> (the id preview-id showed you, e.g. T-HXSS-<slug>).

  5. Body seed. The task body should record where the TODO came from, so it’s traceable. Use Edit to replace the ## Today placeholder block with:

    Surfaced by `/sdlc:review-todos` from `<source-path>:<line>`:
    > <verbatim TODO source line, trimmed>

    Leave the other placeholder sections alone — they’re for the author to fill in via /sdlc:task-define later.

  6. Optional annotation. Ask via AskUserQuestion: “Annotate the TODO in source with a pointer to the new task?” Two options: Yes — append [[<basename>]] to the TODO line (default) and No — leave source untouched.

    If yes: Edit the source file. Find the TODO line and append the wikilink at the end. Build the [[...]] token with wrapWikilink(<basename-without-.md>) from ${CLAUDE_PLUGIN_ROOT}lib/util/wikilinks.ts rather than hand-spelling the brackets. Keep the existing comment marker and text intact; just suffix the wikilink before any trailing comment-close characters if the language has them. Skip the annotation silently if the line already ends with [[...]].

  7. Validate:

    ${CLAUDE_PLUGIN_ROOT}cli/sdlc entities validate <task-path>
  8. Commit. Stage the new task and (if annotated) the source file, then route the message through sdlc commit create:

    git add <task-path> [<source-path>]
    ${CLAUDE_PLUGIN_ROOT}cli/sdlc commit create \
    --subject "docs(planning): create task/<task-basename> from TODO" \
    --body "<source-path>:<line> — <headline>"

Backlog capture is delegated to sdlc backlog create — the deterministic tail that lands the item on the rolling backlog-capture PR and prints a PR: <url> marker. This skill only feeds it structured args. See ${CLAUDE_PLUGIN_ROOT}cli/backlog_cli/README.md for the contract. Triage of captured items is the separate /sdlc:backlog-triage flow.

  1. Derive a headline the same way as in section 3.1 (<headline>). backlog create derives the slug and id from --headline, so there’s no slug to hand off.

  2. Build the body seed so the captured item is traceable:

    Surfaced by `/sdlc:review-todos` from `<source-path>:<line>`:
    > <verbatim TODO source line, trimmed>
    <one-line evaluation from step 2.2, if non-trivial>
  3. Capture it on the rolling backlog PR:

    ${CLAUDE_PLUGIN_ROOT}cli/sdlc backlog create \
    --headline "<headline>" \
    --body "<body seed from step 2>"

    Omit --status — backlog items born from this skill are untriaged on purpose, so /sdlc:backlog-triage picks them up later. The tail prints one PR: <url> line; capture it. If the tail exits non-zero, surface its stderr verbatim (bad slug, schema-validation, or gh/git error).

  4. Optional annotation. Same prompt and placement as 3.6 — build the token with wrapWikilink(<backlog-slug>) and suffix it to the source TODO line. Commit that single source-file edit on main:

    git add <source-path>
    ${CLAUDE_PLUGIN_ROOT}cli/sdlc commit create \
    --subject "docs(planning): annotate TODO with backlog/<backlog-slug>" \
    --body "<source-path>:<line> — <headline>"

    Skip this commit entirely when the user declined the annotation — the backlog file itself already landed on the rolling PR in step 3.

  1. Ask the user in plain text: “What should the comment say now? (or ‘delete’ to remove the line entirely)”.

  2. Use Edit on the source file:

    • If the response is the literal word delete, remove the TODO line (and a single trailing blank line if it leaves a stray gap).
    • Otherwise, replace the TODO line with the user’s text. Preserve the surrounding indentation and the language’s comment prefix (#, //, --, etc.) — infer the prefix from the original line.
  3. Commit only the source file:

    git add <source-path>
    ${CLAUDE_PLUGIN_ROOT}cli/sdlc commit create \
    --subject "chore: tidy TODO at <source-path>:<line>" \
    --body "<short note: 'reworded' or 'removed stale TODO'>"

If the user’s intent for the edit is non-trivial (more than a reword — e.g. they want the code changed too), tell them this skill is intake-only and suggest re-running with Create task instead. Don’t try to do code changes here.

Take no action. Move to the next TODO.

After the loop finishes (or the user stops it), print:

  • N TODOs considered.
  • Per disposition: count of tasks created, backlog items created, comments edited, skipped.
  • The basenames of any new artifacts so the user can git log --oneline or open them.
  • Every “Create task” action produced exactly one new task file at docs/planning/tasks/<id>-<slug>.md (id minted by task create, slug derived from the headline), with its frontmatter passing sdlc entities validate and its body referencing the source path:line.
  • Every “Create backlog item” action landed exactly one new backlog file at docs/planning/backlog/B-NNNN-<slug>.md (id minted by the tail) on the rolling backlog-capture PR, with no status: field set (so it’s picked up by /sdlc:backlog-triage) and its body referencing the source path:line. The tail’s PR: <url> marker was reported back to the user.
  • Each created artifact landed in its own commit. If the user opted into source annotation, that commit also includes the single source-file edit.
  • “Edit in place” commits modify exactly one source file and create no planning artifact.
  • “Skip” actions leave the working tree byte-identical to its pre-decision state.
  • No file outside the scanned source path and docs/planning/ was modified.
  • “Worth it” is judgment, not a heuristic. Default to recommending backlog for vague / speculative TODOs and task only for ones with a clear, bounded ask. When in doubt, skip — the TODO is still there for next time.
  • This skill is intake only: it records a TODO as an artifact and stops there, leaving the TODO’s actual investigation and implementation to /sdlc:task-work later. Promotion to task captures the ask; it never works it.
  • The source annotation ([[<artifact-basename>]]) is just a pointer for human readers; nothing in the tooling depends on it. It’s nice-to-have, not required.
  • Hits inside generated files, vendored dependencies, or fixtures are already skipped by git grep honoring .gitignore. To suppress a noisy checked-in file, add it to .gitignore — don’t expand the project scan todos scanner’s hard-coded exclusions.
  • Comment-marker detection in section 5 is best-effort. For languages with unusual comment styles (e.g. block comments), preserve the original prefix verbatim rather than guessing.
  • Committing model-generated messages. Route the multi-line commits in steps 3, 4, and 5 through the canonical pattern in ${CLAUDE_PLUGIN_ROOT}conventions/commit-messages.md (prefer sdlc commit create; heredoc/git commit -F fallback). Single-line git commit -m drops the body’s multi-paragraph context on conventional-commit parens.