Interactively drive a single task document toward the implementation-ready contract (solutions/ontological/lib/model/entities/task/implementation-ready.md). Walks the user through filling missing or thin sections via AskUserQuestion, edits the body, and commits. Leaves readiness_verified_at to /sdlc:task-ensure-ready; callers should invoke task-ensure-ready after this skill returns to verify the result.
Resources
1Install
npx skillscat add osdlc/osdlc/task-define Install via the SkillsCat registry.
$sdlc:task-define
Usage:
$sdlc:task-define <slug-or-filename>— flesh out the named task
through guided questions until it satisfies the implementation-ready
contract.$sdlc:task-define <absolute-path-to-task-file>— same, by absolute
path. Use this form when invoking from another skill.
This skill IS interactive — it asks the user via AskUserQuestion to
resolve every gap. If the user can't or won't answer, the skill exits
gracefully without forcing a state change (the caller decides what to
do next, typically by invoking $sdlc:task-ensure-ready to record the
incomplete state).
References:
${CLAUDE_PLUGIN_ROOT}/lib/model/entities/task/implementation-ready.md— the contract this skill
fills gaps against.sdlc task resolve <arg>— resolves the argument to an absolute task path
(see${CLAUDE_PLUGIN_ROOT}/lib/model/entities/task/file-resolution.mdfor the
resolution contract it implements, orsdlc task resolve --help).
1. Resolve the task file
Run sdlc task resolve <arg> per${CLAUDE_PLUGIN_ROOT}/lib/model/entities/task/file-resolution.md — the canonical
call + outcome contract. On success capture the absolute path and
basename and continue to Step 2.
This skill uses the interactive ambiguous-policy mode: onAMBIGUOUS: it prompts the user via AskUserQuestion over the--output json candidates and uses the pick. If the user bails (or the
op reports NO TASK FOUND), surface NO TASK FOUND for "<arg>" and stop.
2. Read inputs
- Read the task file end-to-end.
- Read
${CLAUDE_PLUGIN_ROOT}/lib/model/entities/task/implementation-ready.md.
3. Identify gaps
Apply the contract from${CLAUDE_PLUGIN_ROOT}/lib/model/entities/task/implementation-ready.md. For
each requirement that fails or disqualifier that triggers, add an
entry to the gap list with:
- the section or field involved,
- the nature of the gap (missing / thin / wrong-value / disqualified-by),
- what an acceptable resolution looks like (so the user question can
be specific).
Run the mechanical disqualifiers through the deterministic task ops
rather than re-deriving them by reading. This skill must surface the
same gaps $sdlc:task-ensure-ready will (it runs immediately after);
mirror that skill's Step 3 interpretation layer so a gap this skill
fills is a gap the gate agrees on.
The judged requirements stay LLM work: required-section
presence/thinness (a present section whose body is empty, unchanged<...> template text, or too vague to inform the implementer),
required-frontmatter fields, subjective ACs, and Approach deferring a
design decision to "the implementer". Read the body for those. The
LLM-judged corpus-assumption disqualifier is also LLM work, but it has
its own advisory scanner — see "Corpus-assumption advisory" below.
The mechanical disqualifiers run through ONE deterministic composite op,sdlc task gap-report, which runs scan-placeholders + check-claims +
a read of parse-touchpoints (## Areas shape, informational only)
plus required-section presence in a single NO-LLM call and returns
one structured readiness-gap object. Read that one object instead of
fanning out separate calls.
Deterministic gap report. Shell out to the composite op:
scripts/sdlc task gap-report <path> --output jsonSee
sdlc task gap-report --help. It is read-only and emits one JSON
object; the text-mode marker isGAP-REPORT gaps=N sections=N placeholders=N claims=N
(exit 0). A missing/unreadable file isINVALID_INPUT(exit 1) — same
as the sibling read-only doc ops. Map its fields onto the gap list:- Touchpoint shape — read
touchpoints.areas_kind(∈table/prose/missing/bulleted-legacy) andtouchpoints.parse_errors[]. As of v7,## Areasis advisory and## Todayis fully free-form prose — neither is a resolution gate,
and NEITHER of these fields ever becomes a gap. They exist only so
you can narrate the shape to the user if it seems worth mentioning. - Placeholder phrases — each entry in
placeholders[]
(TBD/pick-one/ angle-bracket /empty-table-cell) is a gap;
name the section, the matchedphrase, and theline. The op
passes these through unfiltered; they need no further filtering. - Missing required sections — each
sections[]entry withpresent == falseis a required-section gap. - Claim resolvers — read
claims[], mapping byseverity: eachseverity: "disqualifier"finding is a gap — relay itsmessage
(andline) into the gap description;severity: "warning"is
informational only (no-warning-today; the tier exists for a future
use). The op's owngaps[]array already aggregates the
disqualifiers, so you can iterategaps[]directly for the
disqualifier union and consult the per-category objects
(sections,placeholders,touchpoints,claims) for the full
detail to phrase each user question.
The
gaps[]array is the flat, caller-iterable union of every
deterministic disqualifier (placeholders, missing sections, claims —## Today/## Areasshape is never one of them);has_gapsis true
iff it is non-empty. Iterate it for the union and read the
per-category objects for detail.- Touchpoint shape — read
Capture the command's stdout into a variable and parse it; do not pipe
a command you gate on through tail/head (see${CLAUDE_PLUGIN_ROOT}/skills/CLAUDE.md).
Corpus-assumption advisory (LLM-judged — separate from gap-report)
See ${CLAUDE_PLUGIN_ROOT}/conventions/corpus-assumptions-scanner.md for
what the scanner checks and how to confirm a candidate. Run it as its own
separate call, after reading the deterministic report:
scripts/sdlc task scan-corpus-assumptions <path>Only a candidate you CONFIRM against the cited line is a gap.
If the list is empty, report TASK-DEFINE-ALREADY-READY: <basename> on stdout
and exit without editing or committing. The caller can run$sdlc:task-ensure-ready to formally stamp the verification. Keep the
marker slug-prefixed (see ${CLAUDE_PLUGIN_ROOT}/skills/CLAUDE.md; the
2026-05-28 namespacing pass fixed an outer LLM mistaking this signal for
its own terminal verdict).
4. Resolve gaps one at a time
For each gap, ask the user via AskUserQuestion. Be specific:
- Quote the section header and current content (or "").
- Propose 2-3 plausible options where the gap admits them
(e.g. state downshift options, impact tier). - For free-form content gaps (Goal, Approach, ACs), use AskUserQuestion
to confirm the user wants to draft now ("Draft now" / "Skip for now"
/ "Stop"), then if drafting, ask in plain text for the content.
Apply each answer immediately:
- Branch context — where edits land. Invoke
$sdlc:task-define
only frommain(or from adocs/<basename>spec-only branch).
Per
T-SIHV-task-state-frontmatter-commits-on-main-not-worktree-branch,
task-state frontmatter (state:,readiness_verified_at:,last_reviewed:,definition_gap:,completion_note:,prs:)
belongs onmain; body content belongs on whatever branch the
user is on. This skill edits both kinds in the same commit, so
running it from inside a task worktree would land non-state
frontmatter on the task branch — defer those to a separate
spec-only PR if the gap matters enough to land outside the
implementation diff. - Body content: use Edit to replace the gap region. Preserve the
section header; only the body between headers changes. ## Todayis free-form prose — write whatever orients an
implementer, no required shape.## Areasis advisory: when it reads
best as a table, use| Area | Note |(a package/directory/module
and a one-line gloss); prose or a bulleted list is equally fine.
Neither section is resolved against the codebase, so there is no
existence requirement to satisfy — see${CLAUDE_PLUGIN_ROOT}/lib/model/entities/task/implementation-ready.md.- Frontmatter: use Edit to set the field. Do NOT touch
readiness_verified_at:,touchpoints_verified_at:,definition_gap:,completion_note:, orprs:— those are
task-state fields managed elsewhere ($sdlc:task-ensure-readyowns
the readiness stamp / gap;$sdlc:task-workStep 10.4 ownsprs:;$sdlc:task-close-outownscompletion_note:).
If at any point the user picks "Stop" (or equivalent), jump to Step 6
without further questions.
After every gap is resolved (or the user stops), proceed.
4b. Authoring-time advisory: surface schema-violating fields for "make X validate" ACs
For a task shaped "make file X pass validate_frontmatter.ts,"
surface which fields of X currently fail so the author can
enumerate them in Approach up front. This step is an authoring aid:
it does not gate readiness, does not edit Out-of-scope unless the
user explicitly opts in, and accepts "decline" as a first-class
answer.
Procedure:
Shell out to the scanner:
scripts/sdlc task scan-validate-ac <absolute path to task file>The scanner inspects the task's
## Acceptance criteriasection
for lines that mention bothvalidate_frontmatter.tsand at least
one.mdpath. For each target, it runs the validator and captures
the failing fields. Output is a single JSON object on stdout — see
the op's docstring for the exact shape.Parse the JSON. If
matchedisfalse(no validate-AC found), ortargetsis empty, skip the rest of this step.For each target with at least one
failing_fieldsentry, present
the failures to the user via AskUserQuestion. Quote the path and
list each failing pointer + message. Offer three options:- Inject into Approach — Edit a bullet under the
## Approach
section listing the failing fields (one bullet per target, in
citation order). Format:Known schema-violating fields in <path>: <pointer1> (<message1>), <pointer2> (<message2>), ....
Place the new bullet at the end of the existing Approach body so
ordering of pre-existing steps is preserved. - Add to Out of scope — Edit a bullet under
## Out of scope
naming the fields that are not in scope for this task (e.g.
when the task fixes one field but the file has unrelated
violations). - Decline — leave the body untouched. The advisory was seen and
considered; no edit lands.
- Inject into Approach — Edit a bullet under the
For each target where the file doesn't exist (
exists: false) OR
the validator passed with no failures (failing_fields: []),
surface the finding to the user as informational ("X currently
validates clean — the AC may be a regression guard rather than a
fix") but do not Edit the body. The user may want to revise the
AC; that's their call.Treat user answers as ordinary gap resolutions for the purposes of
Step 5 (re-evaluation) and Step 6 (commit). The commit message
summary should mention the advisory if it landed an edit
("inject schema-violating fields for<path>").
This step runs once per $sdlc:task-define invocation, after the
section-gap pass and before re-evaluation. It is a no-op on tasks
that don't carry a validate-AC, and a no-op when the user declines
the offer.
5. Re-evaluate
Re-read the task file. Re-apply the contract. If gaps remain that the
user did NOT explicitly skip, ask once more. If they remain after that,
treat it as a "Stop" and proceed to Step 6.
6. Commit
If any edits were made:
Run the validator:
scripts/sdlc entities validate <path>If it fails, fix and re-run.
Stage only the task file:
git add <path>.Commit on the current branch:
docs(tasks): flesh out <basename> <one-line summary of what was added>Report on stdout:
TASK-DEFINE-DEFINED: <basename> sections updated: <list>
If no edits were made (user stopped immediately, or there were no
gaps), report TASK-DEFINE-NO-CHANGES: <basename> and exit without
committing.
7. Hand off
Print a one-line pointer:
Next: run $sdlc:task-ensure-ready <basename> to verify and stamp.Notes
- The doc the user lands on is whatever they typed. Don't paraphrase,
reword, or "improve" their content. Apply minimal edits to put their
text into the right section. - If the user wants to rewrite a section that's already populated (not
thin or missing, just wrong), this is the right skill but you should
confirm via AskUserQuestion before overwriting non-empty content. - One commit per run, touching only the task file. Same atomicity
contract as$sdlc:task-ensure-ready. - Gap detection is two calls —
sdlc task gap-report
(deterministic, NO-LLM composite over sections + placeholders +
claims, plus an informational-only read of## Areasshape) plus the
separate corpus-assumption advisory (see${CLAUDE_PLUGIN_ROOT}/conventions/corpus-assumptions-scanner.md). As of
v7,## Todayand## Areasare never resolved against the codebase, so
there is no symbol/path existence probe left in this path at all. - Committing model-generated messages. See
${CLAUDE_PLUGIN_ROOT}/conventions/commit-messages.mdfor the canonical pattern (andsdlc commit create --help); this skill authors multi-line commits from model output, so follow
that convention rather than dropping back to single-line-m. - Branch naming. See
${CLAUDE_PLUGIN_ROOT}/conventions/branch-naming.md. This skill commits on
whatever branch the user is on; if it's the spec-onlydocs/<basename>branch, that's expected —
body refinements land in the spec PR.