work-items-to-jira
Break a work-items.md file (produced by /plan-work-items) into independently-grabbable Jira tickets, one per slice, in a single Jira project. Use when you want to turn a work-items file into Jira tickets, publish work items as Jira issues, or create implementation tickets that ca
Install
npx skills add https://github.com/testdouble/han/tree/main/han-atlassian/skills/work-items-to-jira
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install testdouble-han@llmmart
git clone https://github.com/testdouble/han.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole testdouble/han collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Project Context
- personal config directory: !
bash "${CLAUDE_PLUGIN_ROOT}/scripts/han-config-dir.sh" 2>/dev/null || echo "$HOME/.claude" - project .han/config.md: !
cat .han/config.md 2>/dev/null || echo ""
As your first action, use the Read tool on .han/config.md inside the personal config directory path above. A read
that returns no file is no personal configuration: continue silently. When that file or the project .han/config.md
probe supplies content, apply it per config-rule.md, which governs precedence
between the two files, relative-path resolution, and what to do with a file that reads but cannot be used.
Work Items to Jira Tickets
Take an already-broken-down work-items.md file (produced by /plan-work-items) and publish each slice as a Jira
ticket in a single target project.
The breakdown work — drafting slices, assigning symbolic IDs, specifying dependencies, inventorying references — has already been done upstream. This skill's job is to validate the format, confirm the target, create one ticket per slice through the Atlassian MCP server, link the within-file dependencies, and place the tickets in the chosen column.
Rules
- Every slice posts into one Jira project. This skill does not split work across repos or projects. A
work-items.mdthat names multiple code repos still produces tickets in the single project you name; the repo prose is informational only. - Dependencies are within-file only. Every SYM named in a
Depends online must resolve to another slice in the same file. ADepends onthat names an unknown SYM is a format error to surface for repair. - Symbolic-ID prefixes: accept whatever the input uses. Any uppercase prefix shape is valid (
W-N,V2-N,EV-N, …); the prefix has no effect on Jira placement. - Defaults: issue type
Story, no assignee, reporter taken from the Atlassian MCP identity, and the project's initial status (Backlog). Each is overridable per run; nothing is assigned or moved unless asked. - Parenting is optional and determines the child issue type.
--parent <KEY>accepts an epic or a standard issue (a story, task, or bug). Under an epic, each item is a standard issue (defaultStory). Under a story (any standard issue), each item is a subtask (default the project's subtask issue type). You cannot parent under a subtask.--epic <KEY>is a deprecated alias for--parent; it resolves the same way regardless of the named issue's actual type. - Every slice ticket MUST carry the reference artifacts an implementer needs — API/event contracts, design references, schema docs, runbooks, ADRs, coding standards. Tickets that consume an HTTP endpoint or event payload MUST reference the contract section that defines it. Full include/exclude list in references/reference-artifact-inventory.md.
- NEVER include process artifacts in ticket descriptions. Excluded: iteration histories, decision logs, review
findings, team findings, facilitation summaries, gap analyses, and anything under an
artifacts/subfolder of the plan that is not a contract or design reference. - No screenshot upload or image embedding. Design references are carried as links, not uploaded into Jira. See references/jira-ticket-template.md.
Process
0. Atlassian MCP preflight (hard requirement)
This skill cannot run without a configured and connected Atlassian MCP server. Confirm it is reachable by calling
mcp__claude_ai_Atlassian__getAccessibleAtlassianResources to retrieve the cloud ID(s). If the tool is unavailable, the
call errors, or it returns no accessible resources, stop immediately and tell the user the skill requires the
Atlassian MCP server to be installed, configured, and authenticated. Do not fall back to any other publishing target.
If more than one site is accessible, note which are available; you will confirm the right one while resolving the project in Step 3.
1. Locate the work-items file
If the path is not provided, ask for it. The input is a single work-items.md produced by /plan-work-items. Read it.
Its format is described in references/work-items-file-format.md.
2. Gather the run options
Read these from the arguments and conversation; do not guess defaults the user did not ask for:
- Target project or board —
--project <KEY>(e.g.,ACME) or--board <name/URL>. Required. If absent, ask for it in Step 3. - Parent —
--parent <KEY>(an epic likeACME-12, or a story / standard issue likeACME-34) or an issue URL. Optional. When present, every created ticket is parented to it.--epic <KEY>is accepted as a deprecated alias for the same option; if both are given and name different keys, stop and ask which one. The parent's hierarchy level decides the child issue type (resolved in Step 3): standard issues under an epic, subtasks under a story. - Issue type —
--type <name>. Optional; defaults toStoryat the project top level or under an epic, and to the project's subtask issue type when the parent is a story. - Assignee —
--assignee <accountId or email>. Optional; defaults to unassigned. - Column —
--column <name>. Optional; defaults to the project's initial status (Backlog).
3. Resolve the target against Jira
Using the cloud ID from Step 0, resolve everything concretely now so failures surface before any ticket is created:
Project (required). If given a project key, confirm it with
mcp__claude_ai_Atlassian__getVisibleJiraProjects. If given a board, resolve it to its underlying project (list projects and match; if a board maps to more than one project or is ambiguous, ask the user which project to use). If no project or board was provided, ask for one — do not proceed without a project key.Parent (optional). If a parent was named (
--parent, or the deprecated--epic), fetch it withmcp__claude_ai_Atlassian__getJiraIssueto confirm it exists and is in the target project, then read its issue type's hierarchy level to decide the child mode:- Epic (an epic-type issue, hierarchy level above standard) → children are standard-level issues; the
effective default issue type is
Story. - Standard issue (Story, Task, Bug — hierarchy level 0) → children must be subtasks; the effective default issue type is the project's subtask type (resolved in the next bullet).
- Subtask → stop: a subtask cannot have children. Tell the user to name an epic or a standard issue instead.
Record the parent's key and which child mode applies.
- Epic (an epic-type issue, hierarchy level above standard) → children are standard-level issues; the
effective default issue type is
Issue type. Call
mcp__claude_ai_Atlassian__getJiraProjectIssueTypesMetadatafor the project. Determine the effective default from the parent mode above (no parent or epic parent →Story; story parent → the project's subtask issue type, the one flagged as a subtask in the metadata). Then confirm the chosen type — the--typeoverride when given, otherwise the effective default — both exists in the project and sits at the correct hierarchy level for the parent: under a story it must be a subtask type, otherwise it must be a standard (non-subtask) type. If the chosen type is missing or at the wrong level, surface the available types at the correct level and ask the user to pick one. If a story parent is named but the project exposes no subtask type, stop and tell the user subtasks are not enabled in this project.Assignee (optional). If an assignee was named, resolve it to an account ID with
mcp__claude_ai_Atlassian__lookupJiraAccountId. If unset, leave tickets unassigned.Column (optional). If a column was named, hold it for Step 8. Resolve the matching status when you transition (Step 8), since transitions are per-issue.
4. Validate the format with evidence-based repair
Check the work-items file against the invariants in references/jira-ticket-template.md and references/work-items-file-format.md:
- Heading shape. Every slice heading matches
## <SYM-N> — <title>with an em-dash separator (already-published headings annotated as## <SYM-N> (<KEY>) — <title>are valid too). Depends online. Literal bold marker**Depends on.**, trailing period,None.or comma-separated SYMs.- Within-file blockers. Every SYM named in a
Depends online resolves to another slice in this file. - References block. Present whenever the slice consumes an HTTP endpoint, event payload, design frame, ADR, coding standard, or other named artifact.
- No process artifacts. No links to iteration histories, decision logs, review findings, team findings, facilitation
summaries, gap analyses, or anything under an
artifacts/subfolder that is not a contract or design reference.
When a check fails, attempt evidence-based repair. Pull evidence from the source work-items.md, the parent plan
referenced in its intro, the feature spec in the same folder, sibling files in the plan folder, and the relevant repo's
ADRs / coding standards / docs:
- Malformed heading — propose the corrected shape based on the surrounding text. Cite the line number.
- Missing
Depends online — proposeNone.if no blockers are evident in the slice's prose. Cite the absence. - Unknown-SYM
Depends on— propose either the correct in-file SYM (if a typo is evident) orNone.. Cite the SYM list this file actually defines. - Missing References bullet for an HTTP-consuming slice — propose the contract section link from the parent plan's External Interfaces / API Contracts section. Cite the anchor.
- Missing References bullet for a UI slice — propose the design frame and document path from the feature spec's Visual Reference table. Cite the spec section.
- Process-artifact link found — propose removing the link and (if the slice still needs the context) restating the decision in plain language, with a Plan decisions References bullet naming the ID plus a one-sentence description. Cite the include/exclude list.
After validation, report findings in plain language. For each finding name: (1) what is wrong — slice SYM, line reference, failing invariant; (2) the proposed fill — corrected line, new bullet, removed link; (3) the evidence — file path with line number, document section, or named source.
Then give the user three actions: Continue with fills (apply the repairs to the source work-items.md and proceed),
Correct the fills (user provides the right values; apply those and proceed), or Stop (exit without creating
tickets). If validation passes with no findings, proceed to Step 5.
5. Show the plan for confirmation
Creating Jira tickets writes to a shared system, so confirm before doing it. Present a summary and wait for an explicit yes:
- Destination: the Jira site, the target project (key and name), the parent (if any, named as the epic or story it is and what each item becomes under it — a standard issue or a subtask), the issue type, the assignee (or "unassigned"), and the target column (or "Backlog (default)").
- The tickets to create: a table of every slice that does not already carry a
(<KEY>)annotation.
| SYM | Summary (ticket title) | Depends on |
|---|---|---|
| W-1 | Backend per-list validator generalization | None |
| W-2 | … | W-1 |
State the total count and that reporter will be the authenticated Atlassian user. Do not create anything until the user confirms.
6. Create one ticket per slice
Walk the slices in file order (blocker-first, as authored). Skip any slice whose heading already carries a (<KEY>)
annotation so a re-run resumes cleanly. For each remaining slice, call mcp__claude_ai_Atlassian__createJiraIssue with:
- the cloud ID and target project key,
- issue type = the type resolved in Step 3 (default
Storyat the top level or under an epic; the project's subtask type when the parent is a story), - summary = the slice title (the text after
—in the heading), - description = the rendered slice body (everything below the heading: Summary, Description, any notes, References, Tests, Acceptance criteria). Pass it as Markdown; if the create tool requires ADF, convert it. Confirm the expected format against the tool's input schema.
- parent = the resolved parent key, when a parent was resolved (Step 3) — an epic for standard-issue children, or a
story for subtask children. Use the
parentfield the project's create metadata exposes; for a subtask, Jira requiresparent. Ifparentis rejected for an epic in a company-managed project, surface the legacy "Epic Link" field requirement rather than dropping the parent silently. - assignee = the resolved account ID only when the user provided one; otherwise omit it (unassigned).
- reporter: never set it. Jira records the authenticated MCP user as reporter.
After each successful create, capture the returned Jira key and rewrite that slice's heading in place from
## <SYM-N> — <title> to ## <SYM-N> (<KEY>) — <title> using Edit, so dependencies resolve and re-runs skip it. Report
each creation as created: <SYM-N> -> <KEY>.
7. Link dependencies
Once every slice has a Jira key, build the SYM→key map from the annotated headings and walk each slice's
**Depends on.** line. For each blocker (skip None.):
- Record it durably in the dependent ticket. Rewrite the dependent ticket's
Depends online in its description from symbolic IDs to the blockers' Jira keys (linked), viamcp__claude_ai_Atlassian__editJiraIssue. This survives regardless of native-link support. - Create a native link when available. If the configured Atlassian MCP exposes an issue-link capability, also create an "is blocked by" relationship from the dependent ticket to each blocker. If no issue-link tool is available, say so once in the final report rather than implying native links were made.
Report each as linked: <SYM-A>(<KEY-A>) blocked_by <SYM-B>(<KEY-B>).
8. Place tickets in the target column
By default, leave every ticket in the project's initial status (Backlog) and do nothing here.
When the user named a --column, transition each created ticket toward the matching status: call
mcp__claude_ai_Atlassian__getTransitionsForJiraIssue for the ticket, find the transition whose target status matches
the requested column, and apply it with mcp__claude_ai_Atlassian__transitionJiraIssue. If no transition leads to the
requested column for a ticket, do not force it — report that ticket as left in Backlog and name the column it could not
reach, so the user can move it by hand.
9. Report
Summarize: the project and parent (if any, named as the epic or story it is), the issue type used (noting "subtask" when
items were nested under a story), the assignee (or unassigned), and the column. List every created ticket as
<SYM-N> — <KEY> with its URL, the count of dependency links made (and whether they are native Jira links or
description references), and any slices skipped because they already carried a key. If any step failed, report the error
and confirm the source work-items.md annotations reflect exactly which tickets were created.
Files (han)
-
references
-
jira-ticket-template.md 6.7 KB
# Slice ticket format > Each slice in a `work-items.md` file must follow this format. The skill's validation step (Process Step 4) checks it, > and the create step (Step 6) maps each field onto a Jira ticket. This is the same slice format `/plan-work-items` > emits; the mapping to Jira fields is documented below. The format below is what `/plan-work-items` emits. Required fields appear in the order shown. The `**References.**` block is required whenever the slice consumes any external artifact (HTTP endpoint, event payload, design frame, ADR, coding standard) — omit it only when no external artifact applies. Additional `**Bold paragraph.**` context blocks are allowed between required fields when a slice needs them. ``` ## <SYM-N> — <short descriptive name> **Summary.** Three to five very short, plain-language sentences stating why the work is needed and what is being done. No technical detail and no ID references — plan references live in the References block, each with a one-sentence description. **Work to be done.** - Plain-language bullets stating the actual work, one to two short sentences each, every bullet supporting an acceptance criterion below. - Technical detail, when needed, nests under the plain-language bullet it belongs to: starting points (a file path, a contract, a boundary), never a prescribed edit list or implementation code. *(Optional `**Bold paragraph.**` blocks here — e.g., `**Note on scope boundary.**`.)* **References.** - **Plan decisions** — every plan decision or work unit this slice satisfies, one bullet each: the ID as a link (e.g., `[D-6](feature-implementation-plan.md#d-6-...)`) followed by one short plain sentence saying what it is. Never a bare ID list. Replaces any inline `See plan: ...` reference. - **API contract** — `[<file>#<anchor>](<relative-path>)`. Required when the slice produces or consumes an HTTP endpoint. - **Event contract** — `[<file>#<event-section>](<relative-path>)`. Required when the slice produces or consumes an event payload. - **Design** — design document file path plus frame IDs (purpose). Required for UI slices. Carried as a link/reference in the description; this skill does not upload or embed images into Jira (see "Design and screenshots" below). - **Spec section** — `[feature-specification.md#<anchor>](feature-specification.md#<anchor>)` for the behavior this slice realizes. - **ADR / standard / repo doc** — links to architectural decisions, coding standards, or feature docs the implementer must honor. - Omits any bullet that does not apply. Does not link iteration histories, decision logs, review findings, team findings, facilitation summaries, or any other process artifact. **Acceptance criteria.** - [ ] Each criterion is an observable, verifiable outcome of this slice's own behavior. Test expectations live here (e.g., "Automated tests cover the rejection path"). Never standard operating procedure (commit pushed, CI green, PR opened), and never a prohibition without its validated reason stated alongside it. **Depends on.** `<SYM-N>` (within this file), comma-separated for multiple, or `None.` ``` ## Mapping a slice onto a Jira ticket When the skill creates a ticket for a slice, it maps the slice fields like this: - **Summary (Jira) ← slice title.** The text after `— ` in the `## <SYM-N> — <title>` heading becomes the Jira ticket summary. The `<SYM-N>` symbolic ID is not part of the summary; it is preserved only in the source work-items file's heading annotation. - **Description (Jira) ← the entire slice body.** Everything below the heading — Summary, Work to be done, optional notes, References, Acceptance criteria — is rendered into the ticket description. Pass it as Markdown; if the configured Jira create tool requires Atlassian Document Format (ADF), convert it. Confirm the expected format against the tool's input schema at call time. - **Issue type ← the resolved type.** Defaults to `Story` at the project top level or under an epic. When the work items are nested under a story (`--parent <story-key>`), each item is a subtask and the default becomes the project's subtask issue type. The user may override per run with `--type`; the chosen type must exist in the project's issue-type metadata and sit at the correct hierarchy level for the parent — a subtask type under a story, a standard (non-subtask) type otherwise. - **Parent ← an epic or a story (optional).** `--parent <KEY>` parents every created item. Name an epic and each item is a standard issue (Story by default) under the epic; name a story (any standard issue) and each item is a subtask under the story. Set the new ticket's `parent` field to the resolved key. Modern projects use `parent` for both relationships, and a subtask requires it; some company-managed projects use a legacy "Epic Link" field for epic membership — surface this if `parent` is rejected. You cannot parent under a subtask. `--epic <KEY>` is a deprecated alias for `--parent`. - **Assignee ← none by default.** Do not set an assignee unless the user explicitly provides one. - **Reporter ← the Atlassian MCP identity.** The skill never sets reporter; Jira records the authenticated MCP user as the reporter automatically. - **Status / column ← Backlog by default.** Created tickets stay in the project's initial status (Backlog / To Do). When the user names a different column, transition the ticket to the matching status after creation. ## Dependencies (`**Depends on.**`) After every slice's ticket exists and the SYM→Jira-key map is known, the skill resolves each `Depends on` line: - It links the dependency natively when the configured Atlassian MCP exposes an issue-link capability (an "is blocked by" / "Blocks" relationship between the dependent ticket and its blocker). - It always records the resolved relationship in the dependent ticket so it survives regardless of native-link support: the `Depends on` line in the description is rewritten from symbolic IDs to the blockers' Jira keys (linked). Every SYM in a `Depends on` line must resolve to another slice in the same file. A `Depends on` that names an unknown SYM is a format error to surface for repair, not a silent skip. ## Design and screenshots The GitHub version of this skill uploaded PNGs into the target code repo and embedded same-repo raw URLs in the issue body. That mechanism is GitHub-specific and is **not** part of this skill. For UI-bearing slices, the design reference (document path, frame IDs, and any design-tool URL) is carried as a link in the ticket's References. This skill does not upload attachments to or embed images in Jira tickets. If a slice's design must be visible inside the ticket, add the attachment in Jira by hand after the ticket is created. -
reference-artifact-inventory.md 4.8 KB
# Reference artifact inventory The breakdown work upstream (`/plan-work-items`) is responsible for inventorying artifacts and embedding them in each slice's `**References.**` block. This skill's job is to **verify** those references are complete and correct before creating Jira tickets, and to propose evidence-based fills when they are not. This file defines what belongs in slice References blocks (the include list), what never belongs (the exclude list), and how the skill's validation step reasons about both. ## Include (these belong in slice References blocks and/or the source file's Shared reference artifacts) - **HTTP API contract files** (e.g., the parent plan's "External Interfaces" or "API Contracts" section) and the specific endpoint sections that slices produce or consume. - **Event payload contract files** and the specific event sections. - **Feature specification** (`feature-specification.md`) — sections that define the behavior a slice realizes. - **Design assets** — design document file paths plus specific frame IDs (when the plan or spec maps frames to UI), design-tool URLs, mockup PDFs. These are carried into the ticket as links. This skill does not upload or embed images into Jira; the design reference is a link the implementer follows. - **Schema / migration references** when a slice depends on a not-yet-shipped schema. - **ADRs**, coding standards, and feature documentation that constrain the slice's implementation. - **Runbook skeletons or observability notes** when a slice's acceptance criteria require them. ## Exclude (these never belong in slice References blocks or the Shared reference artifacts section) - Iteration histories (`*-iteration-history.md`, `.evidence-roundN.md`, `.junior-developer-roundN.md`, `.adversarial-roundN.md`, etc.) - Decision logs (`decision-log.md`, `implementation-decision-log.md`) - Review findings (`review-findings.md`, `implementation-review-findings.md`) - Team findings, facilitation summaries, gap analyses, security/UX round notes - Anything under an `artifacts/` subfolder of the plan **unless** it is a contract or design reference (e.g., a `design-frame-verification.md` may be cited; a `team-findings.md` may not). These exist to record how the plan was reached, not what the implementer needs to build. Plan-level decisions that survive into a slice are restated in plain language in the slice description, and cited in the slice's `**References.**` block as the decision ID plus a one-sentence description of what it is — never an inline ID-only breadcrumb, and never a link to the decision log itself. If validation finds a process-artifact link in a slice, the proposed repair is to remove the link and (if the context the artifact held is load-bearing) restate the decision in plain language with a **Plan decisions** References bullet. ## Where each artifact should be cited - When a single artifact applies to **many slices**, it should appear once in the source file's **Shared reference artifacts** section. Slices reference it by anchor instead of duplicating. - When an artifact applies to **a single slice**, it appears inline in that slice's `**References.**` block. ## What validation checks For each slice: - If the slice produces or consumes an HTTP endpoint (detected from slice prose mentioning a route, method, status code, or DTO shape), an **API contract** bullet must be present in `**References.**`. - If the slice produces or consumes an event payload, an **Event contract** bullet must be present. - If the slice has a UI surface, a **Design** bullet should be present in `**References.**` (a link/path plus frame IDs). - A **Spec section** bullet should be present whenever the slice realizes a named behavior from the feature spec. - No process-artifact link is present anywhere in the slice body. ## Missing-artifact handling (evidence-based repair) When validation finds a missing or excluded artifact: - **Missing API contract link** — propose the parent plan's External Interfaces / API Contracts section by file path and anchor, evidenced by the section's existence at that location. - **Missing event contract link** — propose the parent plan's events section, evidenced by the section's existence. - **Missing Design link** — inspect the feature spec's Visual Reference table and inline design references; propose the design frame ID(s) and document path, cited by spec section. - **Process-artifact link found** — propose removal, evidenced by the exclude list above. If the link was load-bearing for context, propose a plain-language restatement with a **Plan decisions** References bullet (ID plus a one-sentence description). Every proposed fill must cite a concrete source — a file path with line number, a document section, or an ADR ID. Fills without evidence are surfaced as gaps for the user to resolve, not silently applied. -
work-items-file-format.md 3.7 KB
# Work-items file format > This file describes the format the skill **reads** from `/plan-work-items`. Unlike the GitHub `work-items-to-issues` > skill, this skill does **not** write per-repo split files: every slice becomes a Jira ticket in a single target > project, so there is one input file and no derived files. There is one file shape to know: - **Source `work-items.md`** — one single file emitted by `/plan-work-items`, covering every slice in the plan. The skill reads this file, creates one Jira ticket per slice, and annotates each slice heading in place with the created ticket key. ## Source file shape (input) The source file lives next to its parent plan (typically in `<feature>/<phase>/work-items.md`) and contains, in order: ### 1. Title ``` # Work Items — <feature or phase name> ``` ### 2. Intro paragraph Links the parent implementation plan and feature spec, and notes that work-item SYMs are for cross-reference only: > Source: [feature-implementation-plan.md](feature-implementation-plan.md). Spec: > [feature-specification.md](feature-specification.md). > > Work items are numbered `<SYM>-N` for cross-reference only. `Depends on` lines refer to other work items in this file. ### 3. Cross-repo work order prose _(may be present; informational only for Jira)_ A `/plan-work-items` file that spans more than one code repo includes a paragraph naming which SYMs ship to which repo. **This skill ignores the repo split for placement purposes** — every slice posts into the one Jira project you name, regardless of which repo implements it. The prose is still copied into ticket context where it clarifies cross-repo ordering, but it never changes which project a ticket lands in. ### 4. Shared reference artifacts _(required when any artifact applies to more than one slice)_ A flat list of artifacts more than one slice references — API contract sections, spec sections, schema docs, ADRs, coding standards. Each entry is a relative link plus the anchor or file path an implementer should jump to. These are carried into each ticket's References as links. ### 5. Slices One slice per `## <SYM-N> — <title>` heading. Slice bodies follow [jira-ticket-template.md](./jira-ticket-template.md). Slices may appear in any order; the skill preserves source order and creates tickets blocker-first as authored. ## Symbolic-ID prefixes Both shapes are valid input: - **Single prefix across the plan.** Every slice uses `W-N` (or any single prefix). This is what `/plan-work-items` currently emits. - **Per-area prefixes.** Different prefixes (e.g., `V2-N` backend, `W-N` frontend, `EV-N` events) are accepted as-is. They have no effect on Jira placement; all slices go to the same project. The skill reads any `[A-Z][A-Z0-9]*-[0-9]+` heading. ## Heading annotation after creation After a slice's Jira ticket is created, the skill rewrites that slice's heading in place from: ``` ## <SYM-N> — <title> ``` to: ``` ## <SYM-N> (<PROJECT-KEY-NNN>) — <title> ``` The `(<PROJECT-KEY-NNN>)` annotation (e.g., `(ACME-142)`) is how the skill resolves symbolic IDs to Jira keys when linking dependencies, and how a re-run knows to skip slices that already have a ticket. Both heading shapes — with and without the key annotation — are valid input, so a partial run resumes cleanly. ## What the dependency step depends on The `**Depends on.**` line in each slice uses the literal bold marker, comma-separates blocker SYMs, and ends with `.` (or is `None.`). Every SYM named in a `Depends on` line must resolve to another slice in this same file; the skill turns those into Jira dependency relationships after all tickets exist. There is no cross-file or cross-project dependency concept in this skill.
-
-
SKILL.md 16.8 KB
--- name: work-items-to-jira description: > Break a work-items.md file (produced by /plan-work-items) into independently-grabbable Jira tickets, one per slice, in a single Jira project. Use when you want to turn a work-items file into Jira tickets, publish work items as Jira issues, or create implementation tickets that can be worked on and tracked in Jira. Requires a configured Atlassian MCP server. Does not produce the work-items file itself — use plan-work-items to break a plan into work items first. Does not post to GitHub — use work-items-to-issues for GitHub issues. argument-hint: "[path to work-items.md] [--project KEY or --board name] [--parent KEY, epic or story (optional; --epic is a deprecated alias)] [--type issue type, default Story] [--assignee accountId or email (optional)] [--column name, default Backlog]" allowed-tools: Read, Write, Edit, Glob, Grep, Bash(find *), mcp__claude_ai_Atlassian__getAccessibleAtlassianResources, mcp__claude_ai_Atlassian__atlassianUserInfo, mcp__claude_ai_Atlassian__getVisibleJiraProjects, mcp__claude_ai_Atlassian__getJiraProjectIssueTypesMetadata, mcp__claude_ai_Atlassian__lookupJiraAccountId, mcp__claude_ai_Atlassian__createJiraIssue, mcp__claude_ai_Atlassian__editJiraIssue, mcp__claude_ai_Atlassian__getJiraIssue, mcp__claude_ai_Atlassian__getTransitionsForJiraIssue, mcp__claude_ai_Atlassian__transitionJiraIssue, mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql, Bash(bash "${CLAUDE_PLUGIN_ROOT}/scripts/han-config-dir.sh") --- ## Project Context - personal config directory: !`bash "${CLAUDE_PLUGIN_ROOT}/scripts/han-config-dir.sh" 2>/dev/null || echo "$HOME/.claude"` - project .han/config.md: !`cat .han/config.md 2>/dev/null || echo ""` As your first action, use the Read tool on `.han/config.md` inside the `personal config directory` path above. A read that returns no file is no personal configuration: continue silently. When that file or the `project .han/config.md` probe supplies content, apply it per [config-rule.md](../../references/config-rule.md), which governs precedence between the two files, relative-path resolution, and what to do with a file that reads but cannot be used. # Work Items to Jira Tickets Take an already-broken-down `work-items.md` file (produced by `/plan-work-items`) and publish each slice as a Jira ticket in a single target project. The breakdown work — drafting slices, assigning symbolic IDs, specifying dependencies, inventorying references — has already been done upstream. This skill's job is to validate the format, confirm the target, create one ticket per slice through the Atlassian MCP server, link the within-file dependencies, and place the tickets in the chosen column. ## Rules - **Every slice posts into one Jira project.** This skill does not split work across repos or projects. A `work-items.md` that names multiple code repos still produces tickets in the single project you name; the repo prose is informational only. - **Dependencies are within-file only.** Every SYM named in a `Depends on` line must resolve to another slice in the same file. A `Depends on` that names an unknown SYM is a format error to surface for repair. - **Symbolic-ID prefixes:** accept whatever the input uses. Any uppercase prefix shape is valid (`W-N`, `V2-N`, `EV-N`, …); the prefix has no effect on Jira placement. - **Defaults:** issue type `Story`, no assignee, reporter taken from the Atlassian MCP identity, and the project's initial status (Backlog). Each is overridable per run; nothing is assigned or moved unless asked. - **Parenting is optional and determines the child issue type.** `--parent <KEY>` accepts an epic or a standard issue (a story, task, or bug). Under an **epic**, each item is a standard issue (default `Story`). Under a **story** (any standard issue), each item is a **subtask** (default the project's subtask issue type). You cannot parent under a subtask. `--epic <KEY>` is a deprecated alias for `--parent`; it resolves the same way regardless of the named issue's actual type. - **Every slice ticket MUST carry the reference artifacts an implementer needs** — API/event contracts, design references, schema docs, runbooks, ADRs, coding standards. Tickets that consume an HTTP endpoint or event payload MUST reference the contract section that defines it. Full include/exclude list in [references/reference-artifact-inventory.md](./references/reference-artifact-inventory.md). - **NEVER include process artifacts in ticket descriptions.** Excluded: iteration histories, decision logs, review findings, team findings, facilitation summaries, gap analyses, and anything under an `artifacts/` subfolder of the plan that is not a contract or design reference. - **No screenshot upload or image embedding.** Design references are carried as links, not uploaded into Jira. See [references/jira-ticket-template.md](./references/jira-ticket-template.md). ## Process ### 0. Atlassian MCP preflight (hard requirement) This skill cannot run without a configured and connected Atlassian MCP server. Confirm it is reachable by calling `mcp__claude_ai_Atlassian__getAccessibleAtlassianResources` to retrieve the cloud ID(s). If the tool is unavailable, the call errors, or it returns no accessible resources, **stop immediately** and tell the user the skill requires the Atlassian MCP server to be installed, configured, and authenticated. Do not fall back to any other publishing target. If more than one site is accessible, note which are available; you will confirm the right one while resolving the project in Step 3. ### 1. Locate the work-items file If the path is not provided, ask for it. The input is a single `work-items.md` produced by `/plan-work-items`. Read it. Its format is described in [references/work-items-file-format.md](./references/work-items-file-format.md). ### 2. Gather the run options Read these from the arguments and conversation; do not guess defaults the user did not ask for: - **Target project or board** — `--project <KEY>` (e.g., `ACME`) or `--board <name/URL>`. **Required.** If absent, ask for it in Step 3. - **Parent** — `--parent <KEY>` (an epic like `ACME-12`, or a story / standard issue like `ACME-34`) or an issue URL. Optional. When present, every created ticket is parented to it. `--epic <KEY>` is accepted as a deprecated alias for the same option; if both are given and name different keys, stop and ask which one. The parent's hierarchy level decides the child issue type (resolved in Step 3): standard issues under an epic, subtasks under a story. - **Issue type** — `--type <name>`. Optional; defaults to `Story` at the project top level or under an epic, and to the project's subtask issue type when the parent is a story. - **Assignee** — `--assignee <accountId or email>`. Optional; defaults to unassigned. - **Column** — `--column <name>`. Optional; defaults to the project's initial status (Backlog). ### 3. Resolve the target against Jira Using the cloud ID from Step 0, resolve everything concretely now so failures surface before any ticket is created: - **Project (required).** If given a project key, confirm it with `mcp__claude_ai_Atlassian__getVisibleJiraProjects`. If given a board, resolve it to its underlying project (list projects and match; if a board maps to more than one project or is ambiguous, ask the user which project to use). If no project or board was provided, ask for one — do not proceed without a project key. - **Parent (optional).** If a parent was named (`--parent`, or the deprecated `--epic`), fetch it with `mcp__claude_ai_Atlassian__getJiraIssue` to confirm it exists and is in the target project, then read its issue type's hierarchy level to decide the child mode: - **Epic** (an epic-type issue, hierarchy level above standard) → children are **standard-level issues**; the effective default issue type is `Story`. - **Standard issue** (Story, Task, Bug — hierarchy level 0) → children must be **subtasks**; the effective default issue type is the project's subtask type (resolved in the next bullet). - **Subtask** → **stop**: a subtask cannot have children. Tell the user to name an epic or a standard issue instead. Record the parent's key and which child mode applies. - **Issue type.** Call `mcp__claude_ai_Atlassian__getJiraProjectIssueTypesMetadata` for the project. Determine the effective default from the parent mode above (no parent or epic parent → `Story`; story parent → the project's subtask issue type, the one flagged as a subtask in the metadata). Then confirm the chosen type — the `--type` override when given, otherwise the effective default — both **exists** in the project and sits at the **correct hierarchy level** for the parent: under a story it must be a subtask type, otherwise it must be a standard (non-subtask) type. If the chosen type is missing or at the wrong level, surface the available types at the correct level and ask the user to pick one. If a story parent is named but the project exposes no subtask type, stop and tell the user subtasks are not enabled in this project. - **Assignee (optional).** If an assignee was named, resolve it to an account ID with `mcp__claude_ai_Atlassian__lookupJiraAccountId`. If unset, leave tickets unassigned. - **Column (optional).** If a column was named, hold it for Step 8. Resolve the matching status when you transition (Step 8), since transitions are per-issue. ### 4. Validate the format with evidence-based repair Check the work-items file against the invariants in [references/jira-ticket-template.md](./references/jira-ticket-template.md) and [references/work-items-file-format.md](./references/work-items-file-format.md): - **Heading shape.** Every slice heading matches `## <SYM-N> — <title>` with an em-dash separator (already-published headings annotated as `## <SYM-N> (<KEY>) — <title>` are valid too). - **`Depends on` line.** Literal bold marker `**Depends on.**`, trailing period, `None.` or comma-separated SYMs. - **Within-file blockers.** Every SYM named in a `Depends on` line resolves to another slice in this file. - **References block.** Present whenever the slice consumes an HTTP endpoint, event payload, design frame, ADR, coding standard, or other named artifact. - **No process artifacts.** No links to iteration histories, decision logs, review findings, team findings, facilitation summaries, gap analyses, or anything under an `artifacts/` subfolder that is not a contract or design reference. When a check fails, attempt evidence-based repair. Pull evidence from the source `work-items.md`, the parent plan referenced in its intro, the feature spec in the same folder, sibling files in the plan folder, and the relevant repo's ADRs / coding standards / docs: - **Malformed heading** — propose the corrected shape based on the surrounding text. Cite the line number. - **Missing `Depends on` line** — propose `None.` if no blockers are evident in the slice's prose. Cite the absence. - **Unknown-SYM `Depends on`** — propose either the correct in-file SYM (if a typo is evident) or `None.`. Cite the SYM list this file actually defines. - **Missing References bullet for an HTTP-consuming slice** — propose the contract section link from the parent plan's External Interfaces / API Contracts section. Cite the anchor. - **Missing References bullet for a UI slice** — propose the design frame and document path from the feature spec's Visual Reference table. Cite the spec section. - **Process-artifact link found** — propose removing the link and (if the slice still needs the context) restating the decision in plain language, with a **Plan decisions** References bullet naming the ID plus a one-sentence description. Cite the include/exclude list. After validation, report findings in plain language. For each finding name: (1) what is wrong — slice SYM, line reference, failing invariant; (2) the proposed fill — corrected line, new bullet, removed link; (3) the evidence — file path with line number, document section, or named source. Then give the user three actions: **Continue with fills** (apply the repairs to the source `work-items.md` and proceed), **Correct the fills** (user provides the right values; apply those and proceed), or **Stop** (exit without creating tickets). If validation passes with no findings, proceed to Step 5. ### 5. Show the plan for confirmation Creating Jira tickets writes to a shared system, so confirm before doing it. Present a summary and wait for an explicit yes: - **Destination:** the Jira site, the target project (key and name), the parent (if any, named as the epic or story it is and what each item becomes under it — a standard issue or a subtask), the issue type, the assignee (or "unassigned"), and the target column (or "Backlog (default)"). - **The tickets to create:** a table of every slice that does not already carry a `(<KEY>)` annotation. | SYM | Summary (ticket title) | Depends on | | --- | ----------------------------------------- | ---------- | | W-1 | Backend per-list validator generalization | None | | W-2 | … | W-1 | State the total count and that reporter will be the authenticated Atlassian user. Do not create anything until the user confirms. ### 6. Create one ticket per slice Walk the slices in file order (blocker-first, as authored). Skip any slice whose heading already carries a `(<KEY>)` annotation so a re-run resumes cleanly. For each remaining slice, call `mcp__claude_ai_Atlassian__createJiraIssue` with: - the cloud ID and target **project key**, - **issue type** = the type resolved in Step 3 (default `Story` at the top level or under an epic; the project's subtask type when the parent is a story), - **summary** = the slice title (the text after `— ` in the heading), - **description** = the rendered slice body (everything below the heading: Summary, Description, any notes, References, Tests, Acceptance criteria). Pass it as Markdown; if the create tool requires ADF, convert it. Confirm the expected format against the tool's input schema. - **parent** = the resolved parent key, when a parent was resolved (Step 3) — an epic for standard-issue children, or a story for subtask children. Use the `parent` field the project's create metadata exposes; for a subtask, Jira requires `parent`. If `parent` is rejected for an epic in a company-managed project, surface the legacy "Epic Link" field requirement rather than dropping the parent silently. - **assignee** = the resolved account ID only when the user provided one; otherwise omit it (unassigned). - **reporter:** never set it. Jira records the authenticated MCP user as reporter. After each successful create, capture the returned Jira key and rewrite that slice's heading in place from `## <SYM-N> — <title>` to `## <SYM-N> (<KEY>) — <title>` using Edit, so dependencies resolve and re-runs skip it. Report each creation as `created: <SYM-N> -> <KEY>`. ### 7. Link dependencies Once every slice has a Jira key, build the SYM→key map from the annotated headings and walk each slice's `**Depends on.**` line. For each blocker (skip `None.`): - **Record it durably in the dependent ticket.** Rewrite the dependent ticket's `Depends on` line in its description from symbolic IDs to the blockers' Jira keys (linked), via `mcp__claude_ai_Atlassian__editJiraIssue`. This survives regardless of native-link support. - **Create a native link when available.** If the configured Atlassian MCP exposes an issue-link capability, also create an "is blocked by" relationship from the dependent ticket to each blocker. If no issue-link tool is available, say so once in the final report rather than implying native links were made. Report each as `linked: <SYM-A>(<KEY-A>) blocked_by <SYM-B>(<KEY-B>)`. ### 8. Place tickets in the target column By default, leave every ticket in the project's initial status (Backlog) and do nothing here. When the user named a `--column`, transition each created ticket toward the matching status: call `mcp__claude_ai_Atlassian__getTransitionsForJiraIssue` for the ticket, find the transition whose target status matches the requested column, and apply it with `mcp__claude_ai_Atlassian__transitionJiraIssue`. If no transition leads to the requested column for a ticket, do not force it — report that ticket as left in Backlog and name the column it could not reach, so the user can move it by hand. ### 9. Report Summarize: the project and parent (if any, named as the epic or story it is), the issue type used (noting "subtask" when items were nested under a story), the assignee (or unassigned), and the column. List every created ticket as `<SYM-N> — <KEY>` with its URL, the count of dependency links made (and whether they are native Jira links or description references), and any slices skipped because they already carried a key. If any step failed, report the error and confirm the source `work-items.md` annotations reflect exactly which tickets were created.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.