/sdlc:import-planning
Generated from solutions/ontological/skills/import-planning/SKILL.md.
Description
Section titled “Description”Walk a project root for planning-shaped prose (READMEs with roadmap
sections, brain-dump notes, dated checklists, issue archives, etc.)
and produce draft task/milestone entities under docs/planning/, so a
project can adopt the SDLC plugin without re-keying its prior planning
history. Spins up a fresh worktree, runs a deterministic scanner,
dispatches one sub-agent per candidate to interpret it, presents a
batched plan for one-shot approval, then shells out to sdlc task create /
sdlc milestone create and Edits the drafted body sections in. Opens a PR
at the end. Pass —auto to skip the confirmation prompt, —dry-run
to stop at the plan, —scope
Allowed tools
Section titled “Allowed tools”ReadBashEditAgentAskUserQuestion
Source
Section titled “Source”Usage:
/sdlc:import-planning— full scan + per-candidate interpretation + batched approval + create entities + open PR./sdlc:import-planning --dry-run— same as above through the batched-plan render, then stop. Never creates worktree, branch, or entity files./sdlc:import-planning --auto— skip the per-candidate confirmation prompt and create every non-skip verdict./sdlc:import-planning --scope <subpath>— restrict the scan to a subdirectory under the project root. Repeatable.
Flags combine: /sdlc:import-planning --auto --scope docs --scope notes is valid.
Project context (don’t re-derive every run):
- The deterministic scanner is
sdlc project scan candidates. It is a Bun-run CLI. Read-only. It walks the project, respects.gitignore, applies default excludes (docs/planning/,.git,node_modules,dist,build,target,__pycache__,.venv,.next,.claude, etc.), filters by extension (.md,.txt,.org), and applies cheap content heuristics. Output is JSON:{candidates: [{path, size, mtime, heuristic_hints: [...]}]}. - Entity creation is delegated. Never reimplement frontmatter/slug/date generation in this skill —
shell out to
sdlc task createandsdlc milestone create. Their--helpis the contract. - Body prose fill is part of the job. The mechanical
sdlc task create/sdlc milestone createrun leaves<...>placeholders in the body sections; this skill replaces them with extracted content where the source supports it, including under--auto. - One PR per invocation. Two commits is fine (one per entity-type batch) if both batches are non-empty.
- Entity-type scope:
taskandmilestoneonly. Other types (bug/epic/feature) don’t have schemas yet — sub-agents that want to nominate one of those should returnentity_type: skipinstead.
1. Parse args and pre-flight
Section titled “1. Parse args and pre-flight”Parse the invocation:
--dry-run(flag) — stop after the batched plan; create no worktree, no branch, no files.--auto(flag) — skip the per-candidate confirmation prompt in Step 6.--scope <subpath>(repeatable) — restrict the scan to subpaths under the project root.
Pre-flight on the main repo (the project root the user invoked from). Probe the four scaffolding signals — a dirty working tree, a worktree-path collision, a branch-name collision, and an open PR on the branch — with one report-only op:
${CLAUDE_PLUGIN_ROOT}cli/sdlc project preflight-worktree import-planning \ --branch chore/import-planning \ --project-root .The op probes .sdlc/worktrees/import-planning for a worktree collision, chore/import-planning
for a branch collision, and gh pr list --head chore/import-planning for an open PR. It is
report-only: it surfaces the signals (dirty + the raw porcelain lines, worktreeCollision,
branchCollision, openPrs, and the convenience anyCollision) and never decides stop/proceed,
never aborts, and never cleans up state. The stop/proceed and consent decisions below are this
skill’s, not the op’s. Parse the JSON (the adapter defaults to --output json).
If dirty is true and the changes would interfere with branching from main, surface this to the
user via AskUserQuestion: “Main has uncommitted changes. Proceed (worktree branches from current
main HEAD), or stop?” Default: stop. Show the porcelain lines so the user sees exactly what is at
risk. Do NOT sweep their work into this skill’s commits.
If anyCollision is true (worktreeCollision, branchCollision, or a non-empty openPrs), stop
and ask the user — there may be an unfinished prior run. Do not delete existing state without
confirmation.
2. Dry-run the scanner first (always — including —dry-run mode)
Section titled “2. Dry-run the scanner first (always — including —dry-run mode)”Before creating a worktree, surface what’s about to be considered:
${CLAUDE_PLUGIN_ROOT}cli/sdlc project scan candidates \ [--scopes <subpath>]... \ --project-root .Forward every --scopes the user passed. Parse the JSON (the op defaults to --output json). The
candidate list is sorted by path for determinism.
- If
candidatesis empty: printNo planning-shaped content found.and exit. Do not create a worktree. - Otherwise proceed to Step 3.
3. Create the worktree
Section titled “3. Create the worktree”Skip this step entirely if --dry-run was passed — --dry-run means “tell me what you’d do, don’t
touch the filesystem.”
Otherwise:
git worktree add .sdlc/worktrees/import-planning -b chore/import-planning mainFrom here on, use absolute paths under the worktree for every file operation. Do not cd the parent
session into the worktree.
4. Re-run the scanner inside the worktree
Section titled “4. Re-run the scanner inside the worktree”The worktree branched from main, so its tree is the same content the main-side scanner saw. Re-run anyway from inside the worktree so the candidate paths are relative to the worktree root the rest of the skill operates on:
${CLAUDE_PLUGIN_ROOT}cli/sdlc project scan candidates \ [--scopes <subpath>]... \ --project-root <worktree-absolute-path>If --dry-run was passed, this re-run is unnecessary — the Step 2 output is the plan input. Use it
directly.
Re-parse the JSON. Each candidate has path (relative to project root), size, mtime, and
heuristic_hints.
5. Dispatch one sub-agent per candidate (single message, parallel)
Section titled “5. Dispatch one sub-agent per candidate (single message, parallel)”For every candidate, dispatch one sub-agent in a single message so they run concurrently. This is the higher-level analysis layer — the scanner gathered cheap signals; the agents apply judgment.
Each sub-agent prompt must include:
- The project root (the worktree absolute path, or the main repo absolute path in
--dry-runmode). - The single candidate this agent owns:
path,size,mtime,heuristic_hints. - Permission to read the candidate file and other read-only inspection (
git log, peeking at nearby files for cross-reference). Sub-agents must not write or mutate state — entity creation is the orchestrator’s job. - The verdict contract (below).
Per-candidate interpretation contract
Section titled “Per-candidate interpretation contract”Each sub-agent does, in order:
- Read the candidate file end-to-end.
- Decide entity type for what the source represents:
milestone— looks like a planned outcome tied to a release (semver, target date, success criteria, “Q3 goals” framing, release-row).task— looks like a discrete piece of work (a bug to fix, a single feature increment, “next steps” with concrete ACs).skip— not actually planning content (install instructions misclassified as roadmap, scaffolding TOC, contributor guide).
- Distill the frontmatter fields and body sections from the source. For tasks: headline, slug
suggestion (kebab-case), Goal, Today, Proposed, Approach, Acceptance criteria, Out of scope,
Dependencies, Discovery context. For milestones: title, Goal, Success criteria, Tasks narrative,
Out of scope, Risks/open questions, Discovery context, plus any obvious frontmatter (version,
target_date, tags). Carry over what the source actually says — quote, paraphrase, summarise.
Don’t invent ACs the source doesn’t justify; leave a section as the original
<...>placeholder if the source has nothing to say for it. - Return a strict JSON object (no surrounding prose) so the orchestrator can aggregate cleanly:
{ "path": "<the candidate path verbatim>", "entity_type": "task | milestone | skip", "headline": "<one-line headline; required when type is task or milestone>", "slug_suggestion": "<kebab-case slug; required when type is task>", "frontmatter": { "status": "<task status: planning/draft|planning/proposed|planning/backlog|open/ready OR milestone status: open/draft|open/planned|open/active>", "impact": "<task only: high|medium|low>", "complexity": "<task only: small|medium|large>", "version": "<milestone only, if a semver appears in the source>", "target_date": "<milestone only, YYYY-MM-DD, if a date appears in the source>", "tags": ["..."] }, "body_sections": { "Goal": "<...>", "Today": "<task only>", "Proposed": "<task only>", "Approach": "<task only>", "Acceptance criteria": ["<AC-1>", "..."], "Out of scope": ["<item>", "..."], "Dependencies": ["<dep>", "..."], "Discovery context": "<...>", "Success criteria": ["<milestone only>"], "Tasks narrative": "<milestone only>", "Risks / open questions": ["<milestone only>"] }, "evidence": ["<source quote or rationale>", "..."]}Omit body_sections keys the source doesn’t support (do NOT pad with <...>; the orchestrator
preserves the template placeholder in that case).
Keep each agent’s response under ~400 words; use general-purpose subagent type.
Single message — every Agent tool call goes in one assistant turn. Sequential dispatch defeats the design.
Aggregate verdicts
Section titled “Aggregate verdicts”When every sub-agent returns, merge their verdicts into a flat list. If any sub-agent failed to
return parseable JSON, treat that candidate as skip and surface the failure in the plan.
6. Build the batched plan and confirm
Section titled “6. Build the batched plan and confirm”Render a single markdown plan for the user. Group strictly by entity_type:
# Import plan
Found <N> candidate(s) → would produce <T> task(s), <M> milestone(s), <S> skipped.
## Tasks (<T>)For each `task` verdict:- `<slug>` — <headline> - Source: `<path>` (<size> bytes, <heuristic_hints>) - Status: <status> · Impact: <impact> · Complexity: <complexity> - Body coverage: Goal/Today/Proposed/Approach/AC<s>/Out-of-scope/Discovery — list which sections were filled vs left as placeholder.
## Milestones (<M>)For each `milestone` verdict:- `<title>` — <headline> - Source: `<path>` (<size> bytes, <heuristic_hints>) - Status: <status> · Version: <version|-> · Target: <target_date|-> - Body coverage: Goal/Success/Tasks/Out-of-scope/Risks/Discovery — list filled vs placeholder.
## Skipped (<S>)For each `skip` verdict, one line: `<path>` — <one-sentence reason>.If --dry-run was passed, stop here. Print the plan. Exit without creating worktree, branch, or
entity files. (If a worktree was somehow created in Step 3 despite --dry-run, that’s a bug — Step
3 must be skipped under --dry-run.)
If --auto was passed, skip the confirmation prompt and proceed to Step 7 with the full
non-skip set.
Otherwise, ask the user via AskUserQuestion with these options:
-
Run the plan as shown (Recommended if it looks right) — proceed to Step 7 with the full non-skip set.
-
Walk one-by-one first — drives a follow-up AskUserQuestion per task/milestone candidate (
create,drop, orchange type to task|milestone|skip), then re-builds the plan with the answers folded in and asks again. -
Cancel — don’t create anything — tear down the worktree and branch this skill created, then exit:
${CLAUDE_PLUGIN_ROOT}cli/sdlc project teardown-worktree import-planning \--branch chore/import-planning \--project-root <worktree-parent-repo-root>The op removes only the named
.sdlc/worktrees/import-planningworktree and deletes onlychore/import-planning— it never sweeps unrelated state, and it is idempotent (a missing worktree or branch is reported, not an error). It honors the global--dry-runflag: under--dry-runit probes and reports intent only, making no git/filesystem writes.
7. Create entities and fill bodies
Section titled “7. Create entities and fill bodies”For each non-skip candidate, in order:
7a. For task candidates
Section titled “7a. For task candidates”From inside the worktree:
${CLAUDE_PLUGIN_ROOT}cli/sdlc task create \ --project-root <worktree-absolute-path> \ --headline "<headline>" \ --status <status> \ --impact <impact> \ --complexity <complexity> \ [--tags <tag>]... \ [--related <slug-or-basename>]...The slug positional is omitted on purpose: task create derives the slug from --headline
([[P-0001]], the shared capped deriveSlug), so the sub-agent’s synthesized headline is the single
source of truth and slug_suggestion does not have to be restated here. (An explicit <slug>
positional still wins if you ever need to override the derivation.) If you want to SHOW or confirm
the would-be slug + id before creating — or check for an existing collision — call the read-only
companion first: sdlc task preview-id "<headline>" --project-root <worktree-absolute-path> (add
--output json for {slug, id, exists, exact_match, similar, warning}). It derives the same slug
create will, so a previewed slug is byte-identical to what gets minted.
Capture the printed path. If the op exits non-zero, stop and report the error verbatim. Do not roll back already-created files; the worktree isolates them from main, and a half-done batch is recoverable by either continuing or abandoning the PR.
7b. For milestone candidates
Section titled “7b. For milestone candidates”${CLAUDE_PLUGIN_ROOT}cli/sdlc milestone create \ --project-root <worktree-absolute-path> \ --title "<headline>" \ --status <status> \ [--version <semver>] \ [--target-date YYYY-MM-DD] \ [--tasks <basename>]... \ [--tags <tag>]...sdlc milestone create assigns ids serially as it runs (M0001, M0002,…), so run milestone
creations sequentially in the same process — do not parallelize. Capture each printed path.
7c. Fill body sections (applies under —auto too)
Section titled “7c. Fill body sections (applies under —auto too)”Each created file has <...> placeholders in its body sections. For every created path, walk the
captured body_sections from the sub-agent’s verdict and use Edit to replace each placeholder block
with the extracted content.
Rules:
- Replace a placeholder block ONLY when the verdict supplied content for that section. Sections the
verdict left empty stay as the original
<...>placeholder. - Preserve the
## <Heading>line itself; only the placeholder body changes. - For bullet sections (Acceptance criteria, Out of scope, Success criteria, Risks/open questions),
replace both the descriptive
<...>blurb AND the example- <...>bullet(s) with the verdict’s bullets. - Do NOT touch the
# <Title>line — the create ops in 7a / 7b already replaced it. - Do NOT add sections the templates don’t have.
- Do NOT carry over source content that doesn’t fit any section. The author can add it by hand later.
- Fill every section the source supports. A file with no sections filled is an extraction failure, not a valid output.
7d. Validate
Section titled “7d. Validate”For every created path:
${CLAUDE_PLUGIN_ROOT}cli/sdlc entities validate <path>If any file fails validation, stop and report. Do not commit a partially-invalid batch.
8. Commit, push, open PR
Section titled “8. Commit, push, open PR”Stage only the created entity files (paths captured in 7a / 7b). Do not git add -A. The narrow
git add is required — sdlc commit create commits the staged index; it does NOT narrow scope.
git add docs/planning/tasks/*.md docs/planning/milestones/M*.md${CLAUDE_PLUGIN_ROOT}cli/sdlc commit create --message - <<'EOF'docs(planning): import <T> task(s) and <M> milestone(s)
Imported from prior planning content in this repo via /sdlc:import-planning.
Tasks:- <basename> — <headline>- ...
Milestones:- M<NNNN> — <title>- ...EOFThe message reaches git through the op’s mktemp’d file (the - sentinel: stdin bytes the shell
does not re-parse), so the conventional-commit parens are safe. See
${CLAUDE_PLUGIN_ROOT}conventions/commit-messages.md.
One commit covering both batches is fine. Split into two commits (one per entity type) if T and M are both non-zero and the diff reads more naturally that way.
git push -u origin chore/import-planninggh pr create --title "Import planning content as tasks/milestones" --body "<see below>"PR body shape:
## Summary
Best-effort extraction of planning content from this repo into SDLCtask/milestone entities. T tasks, M milestones. S candidates skipped.
## Tasks created (<T>)
- `<basename>` — <headline> (<status>) - Source: `<path>`
## Milestones created (<M>)
- M<NNNN> — <title> (<status>) - Source: `<path>`
## Skipped (<S>)
- `<path>` — <reason>
## How this was generated
Invoked `/sdlc:import-planning`. The skill ran`sdlc project scan candidates`, dispatched one sub-agent per candidate(in a single message — parallel), aggregated verdicts, then shelledout to `sdlc task create` / `sdlc milestone create` and Edited thedrafted body sections in.
## Review notes
Body sections were best-effort distilled from the source. Anyremaining `<...>` placeholders indicate sections the source didn'tcover. Reviewers should refine headlines, fill remaining placeholders,and adjust status before merging if any imported entity isn't actuallythe type the skill inferred.Return the PR URL to the user.
9. Report
Section titled “9. Report”Tell the user:
- The PR URL.
- The T task basenames + headlines and M milestone ids + titles, one line each.
- The S skipped paths and their reasons.
- The worktree path (in case they want to push follow-up edits before merging).
- Reminder: this skill never edits the source files. Adding inbound back-references from the source docs to the new entities is the author’s job.
Acceptance criteria
Section titled “Acceptance criteria”- Worktree exists at
.sdlc/worktrees/import-planning, branchchore/import-planning(skipped under--dry-run). - T+M entity files exist under the worktree at
docs/planning/tasks/anddocs/planning/milestones/, all passingsdlc entities validate. - For each created file, every body section the source supported has been filled in. A file whose
source had nothing to say for a section retains that section’s
<...>placeholder; a file with NO sections filled is an extraction failure to investigate. - A single commit (or two, split by type) contains exactly those files (no other changes).
- Branch is pushed; PR is open against the default branch.
- The PR URL was reported back to the user.
Failure modes
Section titled “Failure modes”- Sub-agent returned non-JSON — treat that candidate as
skipand note the failure in the plan. Don’t block the batch on one flaky agent. sdlc task create/sdlc milestone createfailure — stop and surface stderr. The worktree isolates the partial state; user can re-run or abandon.- Validator failure on a freshly-created file — Edit likely corrupted the frontmatter. Stop, report the offending file’s frontmatter back to the user, do not commit.
- No candidates found — exit cleanly after Step 2; do not create a worktree.
- Read-only until Step 7. The scanner is read-only. Sub-agents are read-only (they may shell
git log, but nevergit add/ write). Mutation begins only after the user approves the plan (or--autoskipped the prompt). - Parallelism comes from one message. Step 5 dispatches every Agent call in a single response.
- Type scope is task and milestone only. Bug/epic/feature don’t have schemas yet. The sub-agent
contract enforces this — anything else gets returned as
skip. - No de-duplication. This skill is additive. If a source file was already imported in a prior
run, re-importing creates a second entity — the user can drop it. Out of scope (per the task spec)
to compare against
docs/planning/for collisions. - Eval suite.
${CLAUDE_PLUGIN_ROOT}skills/import-planning/tests/run_evals.test.tsvalidates the scanner against fixtures (mixed, nothing-planning, milestone-vs-task, gitignore-respect). Run it before changing theproject scan candidatesscanner. - Worktree teardown is deferred. This skill does not tear down the worktree after opening the
PR. Cleanup happens after the PR merges;
/sdlc:project-cleanupwill surface the merged branch and its worktree. - Committing model-generated messages. Author the multi-line commit (Step 8) with
sdlc commit create --message -over a quoted heredoc — the message reaches git through the op’smktemp’d file, so the body’s parens never hit a zsh-glob under a bare-m. See${CLAUDE_PLUGIN_ROOT}conventions/commit-messages.md. - Branch naming. This skill’s worktree branch uses
chore/import-planning-<stem>, nottask/<task-basename>. See${CLAUDE_PLUGIN_ROOT}conventions/branch-naming.md.