---
name: plan-story
user-invocable: true
argument-hint: "[--id <N>] [--org <org>] [--project <project>] [--areaPath <area>]"
description: >
  This skill should be used when the user asks to "plan a story", "create a story
  implementation plan", "generate a technical plan for a story", "plan user story",
  "spec out a story", "write an implementation plan", "create tasks for a story",
  "break down a story into tasks", or invokes /jx-pm:plan-story.
  Fetches a User Story from ADO, locates the parent Feature's PRD/TECH_SPEC, explores
  code touchpoints, writes a scratchpad implementation plan, and creates ADO Task
  child items derived from the plan and tech spec.
  Do not trigger for: feature grooming (use refine-feature), feature-level tech specs
  (use /jx-dev:spec), PRD generation (use prd), ADO sync (use ado).
---

# Plan Story

Generate a story-scoped implementation plan from an ADO User Story ID. Fetches the story,
resolves its parent Feature's docs, explores code touchpoints, asks clarifying questions
where ACs are vague, writes a structured plan to `scratchpad/`, then derives and creates
ADO Task child items from the plan and tech spec.

## Step 0: Vendored Content Preflight (required first)

Run this exact check via Bash before any other step. The first line prints the plugin root — capture its output as `<plugin-root>` for every vendored read below.

<!-- vendored-preflight -->
```bash
echo "${CLAUDE_PLUGIN_ROOT}" && \
test -s "${CLAUDE_PLUGIN_ROOT}/_core/id-rules.md" && \
test -s "${CLAUDE_PLUGIN_ROOT}/_core/docs-root.md" && \
test -s "${CLAUDE_PLUGIN_ROOT}/_core/CORE_VERSION" && \
cmp -s "${CLAUDE_PLUGIN_ROOT}/_core/CORE_VERSION" "${CLAUDE_PLUGIN_ROOT}/core-version.txt"
```

- If a `test` clause fails, halt: "This plugin's vendored jx-core content is missing or empty — the install likely did not dereference symlinks (unsupported environment or stale cache). Reinstall with `/plugin install jx-pm@jodex-plugins`; if it persists, file an issue — do not continue, results would be wrong."
- If the `cmp` clause fails, halt: "Vendored jx-core content does not match what this plugin expects — update both plugins: `/plugin update jx-pm` and `/plugin update jx-core`."

## References

- `references/plan-template.md` — required output structure with section definitions
- `<plugin-root>/_core/id-rules.md` — folder naming and ID conventions (root captured in Step 0)
- `<plugin-root>/_core/docs-root.md` — docs root resolution order

## Arguments

| Argument | Required | Default | Notes |
|----------|----------|---------|-------|
| `--id <N>` | Yes | — | ADO User Story work item ID. Prompted if missing. |

---

## Phase 1: Parse Arguments

1. Extract `--id`, `--org`, `--project`, and `--areaPath` from `$ARGUMENTS`.
2. If `--id` is missing → ask: "Which User Story do you want to plan? (ADO work item ID, e.g., `12345`)"
3. Validate `id` is a positive integer.
4. **Pairing rule:** `--org` and `--project` must be supplied together (both or neither).
   If only one is present: **HALT** with:
   > "Both --org and --project are required together — provide both or neither."

---

## Phase 2: Tenant Resolution

Reuse the repo-local tenant resolver from the sibling `create-feature` skill. Do NOT search the filesystem, sibling repos, or parent folders.

**Explicit-flags short-circuit:** If `--org` and `--project` were extracted in Phase 1:
- Set `organization` = `--org`, `project` = `--project`.
- Set `areaPath` = `--areaPath` if provided; otherwise leave it unset (downstream defaults apply).
- Do NOT run `resolve-tenant.sh`. Do NOT read or write `feedback-target.json` on this path.
- Skip to step 4 — validation is required regardless of tenant source.

If NOT using explicit flags:
1. Run: `bash "${CLAUDE_PLUGIN_ROOT}/skills/create-feature/scripts/resolve-tenant.sh"`
2. Parse JSON stdout for `organization`, `project`, `areaPath`.
3. On `ASK_USER` (exit 2): ask user for organization, project, area path. Write `feedback-target.json` in the working-directory root.

Step 4 (always required, regardless of tenant source):
4. Validate project via `mcp__azure-devops__core_list_projects` with `projectNameFilter`.

**Precedence:** explicit flags → resolver → user prompt.

---

## Phase 3: Fetch Story from ADO

1. Call `mcp__azure-devops__wit_get_work_item` with the story ID.
2. **Validate work item type is `User Story`** — if not, halt:
   > "Work item #{id} is a {type}, not a User Story. This skill only plans User Stories."
3. Parse these fields (`System.Parent` is a standard scalar field — no `expand` needed):

| Field | ADO Reference Name |
|-------|--------------------|
| Title | `System.Title` |
| Description / narrative | `System.Description` |
| Acceptance Criteria | `Microsoft.VSTS.Common.AcceptanceCriteria` |
| State | `System.State` |
| Story Points | `Microsoft.VSTS.Scheduling.StoryPoints` |
| Parent Feature ID | `System.Parent` |
| Area Path | `System.AreaPath` |
| Iteration Path | `System.IterationPath` |

4. Display a story summary:

```
## Story #{id}: "{title}"

State: {state}  |  Points: {points or "—"}
Narrative: {as-a / i-want / so-that text, or "[Not set]"}

Acceptance Criteria:
{criteria list or "[None defined]"}
```

---

## Phase 4: Fetch Parent Feature and Locate Docs

### 4a — Fetch parent Feature

1. Use `System.Parent` from the story to get the Feature's work item ID.
2. Call `mcp__azure-devops__wit_get_work_item` on the Feature ID; confirm its type is `Feature`.
3. Parse the Feature's `System.Title` for display.

### 4b — Locate matching docs folder

Search `prd/` (resolved via `docs-root.md` rules) for a PRD whose frontmatter binds this Feature:

```bash
grep -rlE "feature_work_item_id:[[:space:]]*{feature_id}([[:space:]]|$)" prd/
```

The matching file will be one of: `PRD.md`, `BRD_PRD.md`. The folder containing it is the docs root for this Feature.

- If found: read `PRD.md|BRD_PRD.md` for objectives and user stories context; read `TECH_SPEC.md` if present for technical decisions.
- If not found: note "No matching PRD found for Feature #{feature_id} — plan will be based on ADO data only."

---

## Phase 5: Explore Codebase Touchpoints

Use `Read`, `Bash` (grep/find), and `Glob` to explore code areas relevant to the story's ACs:

1. Identify entities, routes, components, or services named in the title or ACs.
2. Search for relevant files: `grep -rn "<keyword>" src/` (adjust root to project structure).
3. List up to 10 most relevant files with a one-line rationale each.
4. If no clear touchpoints found, note this explicitly — do not fabricate.

---

## Phase 6: Clarifying Questions (if needed)

Ask clarifying questions when:
- One or more ACs are vague (e.g., "works correctly", "performs well", no testable outcome).
- The story scope is ambiguous (e.g., "update the UI" without specifying which screen).
- Critical implementation decisions are implied but not stated (API contract, data model).

Present each question individually. Wait for answers before proceeding. Skip this phase if ACs are clear and scope is unambiguous.

---

## Phase 7: Write Plan

Read `references/plan-template.md` for the required sections and formatting.

Write the plan to:
```
scratchpad/{story-title-slug}_{story-id}_plan.md
```

Where `{story-title-slug}` is the story title lowercased, spaces replaced with hyphens, special characters removed (e.g., `add-user-auth_12345_plan.md`).

Report:
```
Plan written: scratchpad/{filename}
```

---

## Phase 8: Identify and Create ADO Tasks

Based on the written implementation plan and the TECH_SPEC (if available), identify the
discrete tasks required to implement the story and create them as ADO Task child items.
Tasks give the team a clear, actionable breakdown and make progress visible in the board.

### 8a — Derive tasks from the plan

Analyze the plan sections — implementation steps, TECH_SPEC technical decisions, and each AC — and
decompose them into atomic, independently-workable tasks. A good task:
- Maps to one AC or one clear implementation step
- Can be completed and verified independently
- Is sized to roughly 1–4 hours of focused work
- Has a clear definition of done in its description

Produce a numbered task list with an hour estimate for each task:
```
## Proposed Tasks for Story #{id}

1. **{task title}** (~{N}h) — {one-line definition of done}
2. **{task title}** (~{N}h) — {one-line definition of done}
...
```

Estimate each task at 1–4 hours based on complexity. Default to 2h when uncertain.

Present this list to the user and ask: "These tasks will be created as ADO child items under Story #{id}. Confirm, adjust titles/descriptions/estimates, or reply 'skip' to skip task creation."

Wait for confirmation before proceeding.

### 8b — Create tasks in ADO

Call `mcp__azure-devops__wit_add_child_work_items` once with all confirmed tasks.
`wit_add_child_work_items` only accepts a limited set of fields per item — do NOT include scheduling fields here:
- `parentId`: the story ID
- `workItemType`: `"Task"` ← top-level field, shared by all items in this call
- `project`: from tenant resolution (Phase 2)
- `items`: one entry per task (each item does NOT repeat `workItemType`):
  - `title`: the task title
  - `description`: the definition-of-done line (expand with the relevant AC or plan step for clarity)
  - `areaPath`: the parent story's `System.AreaPath` (captured in Phase 3) — always set this so tasks land on the same board as the story, not the project default
  - `iterationPath`: the parent story's `System.IterationPath` (captured in Phase 3) — always set this so tasks appear in the same sprint as the story

After all tasks are created, report:
```
Tasks created ({count}):
  #{task_id} {task_title}
  #{task_id} {task_title}
  ...
```

### 8c — Stamp scheduling fields on each task

`wit_add_child_work_items` does not accept scheduling fields, so patch them separately.
For each created task, call `mcp__azure-devops__wit_update_work_item` using the JSON-patch shape:
- `id`: the task's work item ID (from the creation response)
- `updates`: array of patch operations — the `value` must be a **string**, not a number:
  ```json
  [
    { "path": "/fields/Microsoft.VSTS.Scheduling.OriginalEstimate", "value": "2" },
    { "path": "/fields/Microsoft.VSTS.Scheduling.RemainingWork", "value": "2" }
  ]
  ```
  Replace `"2"` with the confirmed estimate as a quoted string (e.g., `"3"` for 3 hours).

Set both fields to the same confirmed hour estimate. `OriginalEstimate` records the initial sizing;
`RemainingWork` starts equal to it so burndown correctly reflects unstarted effort — it decreases
as the team logs work, so initializing to zero would falsely signal the task is already done.

These calls can be made sequentially. On any failure, note the task ID and continue — do not abort the whole phase.

---

## Phase 9: ADO Link-Back

After creating the tasks, post the full plan content as an ADO comment on the story. This makes
the plan immediately visible to the team from the work item without navigating to the repo.

1. Read the full content of the plan file just written (`scratchpad/{filename}`).
2. Compose the comment body:
   ```
   ## Implementation Plan: {story-title}

   > Plan file: `scratchpad/{filename}`

   {full markdown content of the plan file}
   ```
3. Call `mcp__azure-devops__wit_add_work_item_comment` with `workItemId` = story ID and the comment body.
4. Report: "Comment added to story #{id}."

---

## Checklist

- [ ] Story ID provided and validated as a User Story
- [ ] Tenant resolved via repo-local resolver
- [ ] Story fetched and summary displayed (including AreaPath and IterationPath)
- [ ] Parent Feature ID extracted; Feature fetched
- [ ] Docs folder located via `ado_sync.feature_work_item_id` frontmatter match
- [ ] PRD and TECH_SPEC read (if found)
- [ ] Codebase touchpoints explored and listed
- [ ] Clarifying questions asked for vague ACs (if needed)
- [ ] Plan written to `scratchpad/{slug}_{id}_plan.md`
- [ ] Tasks derived from plan + TECH_SPEC with hour estimates, confirmed with user
- [ ] ADO Tasks created as child items of story #{id}
- [ ] Scheduling fields patched on each task (OriginalEstimate = RemainingWork = confirmed estimate hours)
- [ ] Full plan content posted as ADO comment on story #{id}
