---
name: breakdown-to-tickets
description: "Transfers a completed tech breakdown document into Jira tickets. Reads the breakdown's implementation tasks and AI Context section, checks for existing child tickets on the Epic, fills them in or creates new ones. Produces concrete, actionable descriptions from the breakdown: affected files, real function names, code patterns. Wires dependencies as Jira `Blocks` links rather than description prose. Use after finishing a breakdown with /tech-breakdown. Invoke with a Confluence page link (e.g. /breakdown-to-tickets https://...)."
---

# Breakdown to Tickets

## Overview

Take a completed tech breakdown document (produced by `/tech-breakdown`) and turn its numbered implementation tasks into Jira tickets. The Epic already exists (the parent spike ticket). This skill checks for existing child tickets on that Epic, fills them in if they exist, or creates new ones. The output is tickets that any developer can pick up and know exactly what to do.

<HARD-GATE>
Do NOT create or update any tickets until the user has confirmed the full triage plan. Creating one ticket at a time without confirmation wastes time if the matching is wrong.
</HARD-GATE>

## Anti-Pattern: "The Description Can Be Vague, The Developer Will Figure It Out"

Tickets that say "implement X" without specifying which files to touch, what function signatures look like, or what the blocking dependency is force the developer to re-read the whole breakdown before they can start. The breakdown has the answers — put them in the ticket.

## Checklist

1. **Fetch** — read the breakdown doc and identify the Epic
2. **Triage** — check for existing child tickets; match them to breakdown tasks
3. **Confirm** — show the plan (create N, update M) and wait for user approval
4. **Execute** — create and update tickets
5. **Summary** — report what was done with links

---

## Process Flow

```dot
digraph breakdown_to_tickets {
    "Fetch breakdown + find Epic" [shape=box];
    "Query child tickets on Epic" [shape=box];
    "Match tasks to existing tickets" [shape=box];
    "Plan looks correct?" [shape=diamond];
    "User corrects matches" [shape=box];
    "Execute: create + update" [shape=box];
    "Summary" [shape=box];

    "Fetch breakdown + find Epic" -> "Query child tickets on Epic";
    "Query child tickets on Epic" -> "Match tasks to existing tickets";
    "Match tasks to existing tickets" -> "Plan looks correct?";
    "Plan looks correct?" -> "User corrects matches" [label="no"];
    "User corrects matches" -> "Plan looks correct?";
    "Plan looks correct?" -> "Execute: create + update" [label="yes"];
    "Execute: create + update" -> "Summary";
}
```

---

## Phase 1: Fetch & Parse

Create a task for this phase and mark it in progress.

### Get the breakdown page

The user provides a Confluence URL. Fetch the page using `getConfluencePage` with `contentFormat="markdown"`.

If no URL is provided, ask for it.

### Identify the Epic

Look in the **AI Context** section of the breakdown doc, under "Key resources". The parent spike ticket is listed there. That is the Epic.

If the AI Context section is missing or the spike ticket isn't listed, ask the user for the Epic key directly (e.g. `PM-34035`).

### Parse implementation tasks

Read the **Implementation tasks** section. Extract each numbered task:
- Task number and title
- What it is and why it's needed (the "what/why" paragraph)
- Affected files or crates
- **Dependencies** — collect these from anywhere they appear in the task entry (a "Blocked on" line, prose like "depends on…", references to other Task N entries, references to external Jira keys like `PM-XXXXX`). Classify each into one of:
  - **Within-breakdown**: depends on another Task N in this same breakdown (resolved to a real ticket key during Phase 3 execution).
  - **External**: cites a Jira key for a ticket that lives outside this breakdown (other team's work, runtime framework prerequisites, etc.).
- Any code snippets in the task entry

Store these as the canonical task list. Do not proceed until you have at least one task.

---

## Phase 2: Triage

Mark Phase 1 complete. Create a task for this phase and mark it in progress.

### Query existing child tickets

Use JQL to find all child tickets on the Epic:

```
parent = EPIC-KEY ORDER BY created ASC
```

Fetch enough fields to match: `summary`, `status`, `key`.

### Match tasks to tickets

For each breakdown task, check if any existing child ticket is a plausible match. Matching criteria (in order of confidence):

1. **High confidence**: ticket summary contains the task title verbatim, or vice versa
2. **Medium confidence**: ticket summary shares 3+ significant words with the task title
3. **No match**: nothing close enough

Do not guess at low-confidence matches. It is better to mark a task as "create new" than to incorrectly pair it with the wrong ticket.

If existing tickets are present but none match a task, list them as **unmatched existing tickets** and ask the user whether to ignore them or pair them manually.

### Step 1: Present the overview

Show the full triage table so the user can see the big picture before discussing details. Include the planned `Blocks` link graph so the user can confirm dependencies as well as task matches:

```
Triage plan (9 tasks):

  Task 1: Add session storage infrastructure
    → UPDATE  PM-34056  "Add session storage" (matched)

  Task 2: Implement load_from_state
    → CREATE  (no existing ticket found)
    Blocked by: Task 1

  Task 3: Implement unlock_from_state + generate_session_key
    → UPDATE  PM-34057  "Session key generation" (matched)
    Blocked by: Task 2, PM-31879 (external)

  Task 4: Wire ClientContext construction in main.rs
    → CREATE  (no existing ticket found)
    Blocked by: Task 2, Task 3

  ...

  Unmatched existing tickets (will not be touched):
    PM-34058  "Set up CI for bw crate" — does not correspond to any breakdown task

Does the overall shape look right? If you want to change anything — adjust a match, split a
task, change a summary, add/remove a dependency — tell me which task numbers and we'll go
through them one at a time. Otherwise reply "go" to proceed.
```

### Step 2: Resolve flagged tickets one at a time

If the user flags any tasks (e.g. "task 2 and task 4"), work through them **one at a time**:

1. Show the proposed ticket in full: summary, action (create/update), and the complete description that would be written
2. Ask what they want to change
3. Apply the change and confirm it
4. Move to the next flagged task

Do not show the next flagged task until the current one is resolved. This is the same "one at a time" principle as Phase 2 in tech-breakdown: focused decisions, not a list to review.

### Step 3: Final confirmation

After all flagged tasks are resolved, re-show the updated overview (only showing what changed) and ask for final confirmation before executing:

```
Updated plan:

  Task 2: Implement load_from_state  [summary updated]
    → CREATE  (no existing ticket found)

  Task 4: Wire ClientContext construction in main.rs  [matched to PM-34059]
    → UPDATE  PM-34059  "Wire up main.rs"

Everything else unchanged. Ready to create and update tickets?
```

Wait for explicit confirmation before Phase 3.

---

## Phase 3: Execute

Mark Phase 2 complete. Create a task for this phase and mark it in progress.

Work through the task list **in dependency order** (tasks that block others first) so the within-breakdown blockers exist as real ticket keys by the time later tasks need to reference them.

### Creating a new ticket

Use `createJiraIssue` with:
- `issueTypeName`: `"Task"` (implementation tasks are technical work)
- `summary`: the task title from the breakdown, prefixed with the task number if it helps ordering (e.g. `"[4] Wire ClientContext construction in main.rs"`)
- `description`: see **Ticket Description Format** below
- `parent`: the Epic key

### Updating an existing ticket

Use `editJiraIssue` to set the description field. Preserve any existing description content by appending the new content below a separator:

```
---
*Implementation details (from tech breakdown):*

[new structured content below]
```

If the existing description is empty or only contains a placeholder, replace it entirely.

Do not change the ticket summary unless the user has explicitly asked for it.

### Record the ticket's Jira key

After each create/update, store the resulting Jira key alongside the breakdown's task number. The next step (link creation) and any later tasks that depend on this one will need to reference it.

### Create issue links for dependencies

**After the ticket exists, immediately create its `Blocks` links** using `createIssueLink`. Use the same `type: "Blocks"` for all dependency relationships — Jira's directional semantics handle the rest. For each dependency on this task:

- `inwardIssue`: the blocker (the dependency)
- `outwardIssue`: this task's ticket (the blocked)
- `type`: `"Blocks"`

Both within-breakdown blockers (resolved to real keys recorded earlier in this phase) and external Jira tickets cited in the breakdown go through the same link mechanism. Do not put dependency information in the description body — the link graph is the source of truth.

If the breakdown describes a dependency on something that isn't a Jira ticket (e.g. "the runtime framework's appdata-dir resolver"), skip the link. Don't fabricate a ticket key, and don't fall back to mentioning the dependency in the description.

### Confirm each ticket to the user as it's done

After each create/update and its links, print one line: `✓ PM-XXXXX — Task N: [title]` (followed by `[+N links]` if any were created).

---

## Ticket Description Format

This is the core of the skill. Descriptions must be concrete enough that a developer can start without reading the full breakdown.

```markdown
## What and why
[One short paragraph from the breakdown: what this task does and why it's needed in the context
of the overall feature.]

## Affected files / crates
- `crates/bitwarden-core/src/path/to/file.rs`
- `crates/bw/src/main.rs`
[List the files or crates named in the breakdown. If a file doesn't exist yet, say so: "(new file)".]

## Implementation notes
[The substantive part. Include from the breakdown:]
- Real function names and signatures
- Real type names
- Code patterns or snippets
- What the implementation should produce or expose
- What NOT to do if the breakdown calls it out

[If the breakdown has a code block for this task, include it here verbatim.]

## Reference
- Breakdown doc: [link to the Confluence page]
- Epic: [EPIC-KEY]
```

**Rules for the description:**

- **Do not include a "Blocked on" section.** Dependencies live in Jira's link graph (created in Phase 3), not in the description. A reader who wants to know what blocks this ticket should look at the Jira sidebar, not scan the description.
- Do not include acceptance criteria. Implementation tasks have a definition of done that is evident from the code: it compiles, the tests pass, the feature works.
- Do not mention tests explicitly. Writing tests is implicit.
- Do not add scope that isn't in the breakdown. If the breakdown doesn't say to do something, don't put it in the ticket.
- Do not use vague language like "handle edge cases" or "implement as needed". Every sentence should name a specific thing.

**Inline references are fine when they add context, not when they're the dependency record.** E.g. "this is the SDK-level building block that `bw sync` (Task 3) consumes" is useful prose. "Blocked on Task 1 (PM-XXXXX)" is duplicating the link graph and should be omitted.

---

## Phase 4: Summary

Mark Phase 3 complete. Create a task for this phase and mark it in progress.

Print a summary that includes the link count so the user can confirm the dependency graph was wired up:

```
Done. Created 2 tickets, updated 3 tickets, created 7 Blocks links.

Updated:
  PM-34056  Task 1: Add session storage infrastructure
  PM-34057  Task 3: Implement unlock_from_state + generate_session_key
  PM-34059  Task 5: ...

Created:
  PM-34100  Task 2: Implement load_from_state
  PM-34101  Task 4: Wire ClientContext construction in main.rs

Source: [Confluence page link]
Epic:   [Epic link]
```

Mark Phase 4 complete. The skill is done.

---

## Edge Cases

### The Epic key can't be found in AI Context

Ask the user: "I couldn't find the parent Epic in the AI Context section. What's the Jira key for the Epic? (e.g. PM-34035)"

### The breakdown has no AI Context section

Still proceed. Parse the Implementation tasks section and ask the user for the Epic key.

### A task in the breakdown has no affected files listed

Write what's available. Don't fabricate file paths. If the breakdown is genuinely missing this information, note it in the ticket: "Affected files not specified in breakdown — see the full breakdown doc for context."

### Existing ticket is already well-described

If the existing ticket already has a detailed description (not just a placeholder), ask the user before overwriting:

"PM-XXXXX already has a description. Append the breakdown details below it, or replace it entirely?"

Default to appending.

### Jira project requires fields not in the breakdown

Use `getJiraIssueTypeMetaWithFields` to check required fields, then ask the user for values before creating. Do not guess at field values.
