make-jira-from-spec
Turn spec changes into Jira work items. Reads the .ai/spec/
changes from the current session or a PR, brainstorms the
decomposition, creates or updates Epics and Stories, then
estimates and risk-assesses every item.
Defaults
| Setting | Value |
|---|---|
| Project key | OLS |
| Cloud ID | redhat.atlassian.net |
| Content format | markdown |
| SP field | customfield_10028 |
| Risk Score field | customfield_10976 |
| Epic Size field | customfield_10795 |
| Max story points | 5 (split if above) |
Invocation
/make-jira-from-spec
/make-jira-from-spec https://github.com/org/repo/pull/123
/make-jira-from-spec https://github.com/org/repo1/pull/10 https://github.com/org/repo2/pull/20
/make-jira-from-spec OLS-1234
Arguments (all optional, can be combined):
- PR URL(s) — one or more PR URLs to fetch spec diffs from (spec changes often span multiple repos)
- Jira key — existing Epic or Story to update
Step 1: Gather Spec Changes
Resolve the spec changes using this priority:
1a. PR URL(s) provided
Fetch the diff from each PR with gh pr diff <URL>. Filter
to files under .ai/spec/. When multiple PR URLs are given,
collect spec diffs from all of them — spec changes often
span multiple repos. Read the full content of each changed
spec file.
Overlap detection. If the same spec file appears in
multiple PR diffs, fetch the head revision from each PR
(gh pr view <URL> --json headRefOid) and compare the
file at each head. Flag the overlap to the user before
proceeding — do not silently pick one version. Ask which
PR's version to use as the baseline for decomposition.
1b. Session context (no PR URLs)
Find spec files changed in the current session across all repos in the workspace:
# From the workspace root
for repo in */; do
git -C "$repo" diff HEAD -- .ai/spec/ 2>/dev/null
done
Also check for untracked new spec files:
for repo in */; do
git -C "$repo" diff --cached -- .ai/spec/ 2>/dev/null
git -C "$repo" ls-files --others --exclude-standard .ai/spec/ 2>/dev/null
done
1c. Neither is clear
Ask the user:
I couldn't detect spec changes in this session. Can you point me to the PR or spec files that changed?
Read the full content of every changed spec file — the diff alone is not enough context for good decomposition.
Step 2: Brainstorm Decomposition
Invoke superpowers:brainstorming with the spec changes as
context. The brainstorming session should produce:
- What Epics are needed (if the scope warrants them)
- What Stories are needed under each Epic
- Summary and Acceptance Criteria for each item
- Which items map to existing Jira issues (if a parent was provided)
- What e2e / integration test stories are needed — every implementation story MUST have a corresponding test story (or test AC within the story itself).
Feed the brainstorming session with:
- The full spec content (not just the diff)
- The diff showing what changed
- The existing Jira parent and its children (if known)
- An explicit prompt: "For each implementation story, identify what e2e or integration tests are needed. Create separate test stories when the testing effort is non-trivial (new test fixtures, new test scenarios, cross-repo validation). Include test criteria in the AC of the implementation story when the test is a straightforward extension of existing tests."
Test coverage gate. If the brainstorming output includes implementation stories without test coverage, do NOT proceed to Step 3. Present the gap to the user and ask whether to add test stories, add test AC, or explicitly waive testing for those items.
The brainstorming output is the proposed work breakdown — it is NOT yet approved for Jira creation.
Step 3: Resolve Parent
Determine the parent for new Stories based on what the user provided as the starting context.
Do NOT create Epics or Stories under Feature Requests. A Feature Request is a source of context, not a parent container. Stories must be under an Epic, never directly under a Feature or Feature Request.
3a. Starting context is an Epic
The Epic itself is the parent for any new Stories. The Epic's description may also need updating to reflect the spec changes (handled in Step 6).
3b. Starting context is a Feature
The Feature may need its description updated, but Stories cannot be created directly under a Feature — they need an Epic parent. Search the Feature's existing children for a matching Epic:
searchJiraIssuesUsingJql:
cloudId: redhat.atlassian.net
jql: >
parent = {FEATURE_KEY}
AND issuetype = Epic
AND resolution = Unresolved
fields: ["summary", "status"]
maxResults: 100
- If an existing Epic fits → propose it as the parent
- If no Epic fits → ask the user which Epic to use or whether to create a new one
3c. Starting context is a Feature Request, or no Jira key provided
Search for existing open Epics by keyword from the Feature
Request summary and the proposed stories. Strip JQL reserved
characters (-, (, ), [, ], ", ', +, &,
|, !, {, }) from the search terms before building
the query:
searchJiraIssuesUsingJql:
cloudId: redhat.atlassian.net
jql: >
project = OLS
AND issuetype = Epic
AND resolution = Unresolved
AND summary ~ "{escaped keywords}"
fields: ["summary", "status", "labels"]
maxResults: 20
Run multiple queries if the proposed stories span different areas — use the most distinctive terms from each story cluster, not generic words like "OLS" or "support".
If matching Epics are found, present them:
Found existing Epics that may match:
| # | Key | Summary | Status |
|---|----------|---------------------------------|------------|
| 1 | OLS-2001 | {summary} | Refinement |
| 2 | OLS-2005 | {summary} | In Progress|
Options:
1, 2, ... — use this Epic as the parent
new — create a new Epic (will be top-level, no parent)
key — enter a different Epic key
If no matching Epics are found, skip the table:
No open Epics match these stories. Options:
new — create a new Epic (I'll draft summary & scope)
key — provide an existing Epic key (e.g. OLS-1234)
Wait for user confirmation. Do NOT proceed without a confirmed parent Epic.
When the user chooses "new", the Epic is created as a top-level item (no parent). This is the one exception to the "parent is required" constraint — Epics from the FR path are explicitly top-level.
Step 4: Search Existing Jira Items
Query children of the user-provided parent only:
searchJiraIssuesUsingJql:
cloudId: redhat.atlassian.net
jql: >
parent = {PARENT_KEY}
OR "Epic Link" = {PARENT_KEY}
fields: ["summary", "description", "status",
"issuetype", "customfield_10028",
"customfield_10976"]
maxResults: 100
Match existing items against the proposed work breakdown:
- Items that already cover proposed work → mark for update
- Proposed items with no match → mark for creation
- Existing items not in the proposal → leave untouched
Step 5: Propose Work Items
Present the full plan to the user:
Spec changes: {list of changed spec files}
Parent: {PARENT_KEY} — {parent summary}
## New Items
| # | Type | Summary | AC count | Test |
|---|-------|----------------------------|----------|------|
| 1 | Epic | {summary} | — | — |
| 2 | Story | {summary} | 4 | AC |
| 3 | Story | {summary} | 3 | #4 |
| 4 | Story | e2e: {test summary} | 3 | covers #2,#3 |
## Updates to Existing Items
| Key | Change | Test |
|----------|-------------------------------------|------|
| OLS-1234 | Update AC to reflect new constraint | AC |
| OLS-1235 | Add scope from new spec section | #4 |
For updates, the Test column reflects whether the *changed
scope* has test coverage, not whether the existing story
has any tests.
**Test column values:**
- `AC` — test criteria are in the story's own acceptance criteria
- `#N` — covered by a dedicated test story (row N)
- `covers #N` — this IS the test story covering row N
- `waived` — user explicitly waived testing at Step 2
- `—` — not applicable (Epics only)
- `NONE` — **gap: no test coverage.** Must be resolved before approval.
If any implementation story shows `NONE`, flag it and
change the approval options:
⚠ Test coverage gaps:
- Story #3 "{summary}" has no test coverage. → Add test AC, create a test story, or justify why no test is needed.
Options: approve-with-gaps — create all items, leaving test gaps (provide justification for each gap) revise — add test coverage first stop — cancel
When the user chooses `approve-with-gaps`, ask for a
justification for each gap. Record it in the story's
Testing section as: `Testing waived — {reason}`.
When no stories show `NONE`, use the standard options:
Options: approve — create/update all items in Jira revise — tell me what to change stop — cancel
**Wait for the user.** Do NOT touch Jira without explicit
approval. The `approve` option is only available when all
stories have test coverage. If gaps exist, only
`approve-with-gaps` may proceed.
## Step 6: Execute in Jira
Before the first Jira call, resolve the **cloudId** by
calling `getAccessibleAtlassianResources` and picking the
`redhat.atlassian.net` site.
### Label inheritance
If the starting context is a Feature Request or Feature,
fetch its labels:
getJiraIssue: cloudId: {cloudId} issueIdOrKey: "{FR or Feature key}" fields: ["labels"]
These labels are passed via `additional_fields` on every
`createJiraIssue` call below — both Epics and Stories.
### Creating items
Create Epics first, then implementation Stories, then test
Stories (so test Stories can reference their parent Epic and
the implementation Story keys). After creating each test
story, update the corresponding implementation story's
Testing section with the test story's key (`Covered by
OLS-XXXX`).
createJiraIssue: cloudId: {cloudId} projectKey: OLS issueTypeName: {Epic | Story} summary: "{summary}" description: "{markdown description with AC}" contentFormat: "markdown" parent: "{parent key}" additional_fields: labels: ["{inherited labels}"]
**MANDATORY** — transition every created item immediately.
This is the most commonly skipped step — treat it as part
of the creation, not a follow-up.
Transition from **New** to **Refinement** (transition ID
`31`):
transitionJiraIssue: cloudId: {cloudId} issueIdOrKey: "{newly created key}" transition: id: "31"
Then **verify** the transition succeeded:
getJiraIssue: cloudId: {cloudId} issueIdOrKey: "{newly created key}" fields: ["status"]
If the status is still New after the first attempt, retry
the transition once. If it fails again (two attempts total),
report the error to the user — do not silently continue.
This applies to every created Epic and Story. Do not
proceed to the next item until the transition is confirmed
or the error is reported.
### Updating items
Fetch the current description first, then merge changes.
Also add any inherited labels that the item doesn't already
have:
editJiraIssue: cloudId: {cloudId} issueIdOrKey: "{issue key}" fields: description: "{updated markdown}" labels: ["{existing labels}", "{inherited labels}"] contentFormat: "markdown"
Preserve any content in the existing description that is not
being replaced. Append new AC, update changed sections, do
not remove sections the spec didn't touch.
### Description format
Fill in the Testing section with one or more of these lines
(one per line, combine when a story needs multiple types):
- `e2e: {what e2e test verifies this story}`
- `integration: {what integration test verifies this story}`
- `Covered by OLS-XXXX (dedicated test story)`
- `Covers: OLS-XXXX (this IS the test story for that item)`
- `Unit tests only — no user-facing behavior change`
- `Testing waived — {reason}` (only when user chose approve-with-gaps)
Omit the Testing section only for Epics.
Use markdown with this structure:
```markdown
## User Story
As a {persona}, I want {goal} so that {benefit}.
## Description
{Context, background, technical detail from the spec.}
## Acceptance Criteria
- {AC 1}
- {AC 2}
## Testing
{selected testing line}
## Spec Reference
Source: {repo}/.ai/spec/{path}
For Epics, omit the User Story section and use:
## Overview
{What this Epic covers and why.}
## Scope
- {Scope item 1}
- {Scope item 2}
## Spec Reference
Source: {repo}/.ai/spec/{path}
Step 7: Estimate and Assess
After all items are created/updated, run the estimation and risk assessment skills on every item. Pass all keys at once to each skill.
Stories
Invoke /estimate-story with all story keys:
/estimate-story OLS-1001 OLS-1002 OLS-1003
Invoke /estimate-risk with all story keys:
/estimate-risk OLS-1001 OLS-1002 OLS-1003
Epics
Invoke /estimate-epic with all epic keys:
/estimate-epic OLS-2001
Step 8: Auto-Split Oversized Stories
After estimation, check every story. If any story was estimated at more than 5 SP:
8a. Brainstorm the split
Use superpowers:brainstorming to break the oversized story
into smaller stories, each targeting ≤ 3 SP.
Sibling Epic decision. Create a new sibling Epic only when the split produces ≥ 3 stories that share a distinct concern not covered by the existing parent Epic's scope (e.g., the parent covers backend API and the split produces 3+ frontend stories). Otherwise, keep all sub-stories under the original parent — do not create an Epic for fewer than 3 stories or for stories that fit the parent's scope.
8b. Present split for approval
Story OLS-1002 estimated at 8 SP — splitting:
| # | Summary | Parent | Test |
|---|----------------------------|---------------------|------|
| 1 | {sub-story 1} | OLS-2001 | AC |
| 2 | {sub-story 2} | OLS-2001 | #3 |
| 3 | e2e: {test summary} | OLS-2002 (new Epic) | covers #2 |
Apply the same test coverage gating as Step 5: if any
sub-story shows NONE, only offer approve-with-gaps.
Options:
approve — create the split (only when all sub-stories have test coverage)
approve-with-gaps — create the split, leaving test gaps
revise — tell me what to change
Wait for user approval.
8c. Execute the split
Follow the same creation procedure as Step 6:
- Create new Epic (if proposed) via
createJiraIssue— include inherited labels viaadditional_fields - Create the smaller stories via
createJiraIssue— include inherited labels viaadditional_fields - Transition every newly created item to Refinement
(transition ID
31), then verify the status. If still New after the first attempt, retry once. If it fails again (two attempts total), report the error and continue. - Close or update the original oversized story — add a comment noting it was split, link to the new stories
- Re-run
/estimate-storyand/estimate-riskon the new stories - Re-run
/estimate-epicon all affected Epics
Step 9: Report
Feature Request summary comment
If the starting context was a Feature Request, post a summary comment on it listing all final work items (after any splits in Step 8). Use bare issue keys for Jira auto-linking — do not wrap them in brackets:
addCommentToJiraIssue:
cloudId: {cloudId}
issueIdOrKey: "{FR key}"
commentBody: |
Work items created from this Feature Request:
Source: {spec file path(s)}
Epics:
- OLS-2001 — {epic summary}
Stories:
- OLS-1001 — {story summary} (under OLS-2001)
- OLS-1002 — {story summary} (under OLS-2001)
Created by make-jira-from-spec.
contentFormat: "markdown"
Summary table
Print a summary table of everything created and updated:
## Summary
| Key | Type | Summary | SP | Risk | Test | Status |
|----------|-------|----------------------|----|------|------|---------|
| OLS-2001 | Epic | {summary} | — | — | — | Created |
| OLS-1001 | Story | {summary} | 3 | 2 | AC | Created |
| OLS-1002 | Story | {summary} | 2 | 1 | #1003| Created |
| OLS-1003 | Story | e2e: {test summary} | 2 | 1 | covers #1002 | Created |
| OLS-1234 | Story | {summary} | 3 | 2 | AC | Updated |
Epics sized: OLS-2001 → S (15 SP)
Spec sources:
- lightspeed-service/.ai/spec/what/query-pipeline.md
- lightspeed-operator/.ai/spec/what/deployment.md
Constraints
- Human gates are mandatory — never create or update Jira issues without explicit user approval (Step 5, Step 8b).
- Parent is required — always ask if not provided. Do not create orphan stories. Exception: Epics created from the Feature Request path are top-level (no parent).
- Scoped search only — when searching for existing items, only look at children of the user-provided parent. Do not search the entire project.
- Preserve existing content — when updating an issue, merge changes into the existing description. Do not overwrite sections the spec didn't touch.
- Max 5 SP per story — any story estimated above 5 SP must be split. This is not optional.
- Spec reference required — every created item must include a Spec Reference section linking back to the source spec file.
- No invented requirements — only create work items for scope that exists in the spec. Do not expand scope.
- Use markdown contentFormat — all Jira descriptions use
contentFormat: "markdown". The Jira MCP server converts to ADF automatically. - Label inheritance — when the starting context is a Feature Request or Feature, copy its labels to every created and updated item (Steps 6 and 8c).
- Transition verification — after transitioning any item to Refinement, verify the status. Retry once if it fails. Report the error after two attempts total.
- FR summary comment in Step 9 — the comment on the Feature Request is posted in Step 9, after all items (including splits) are final. Use bare issue keys for Jira auto-linking.
- JQL escaping — strip reserved characters (
-,(,),[,],",',+,&,|,!,{,}) from search terms before building JQL queries. - Test coverage required — every implementation story
must have test coverage: either test criteria in its own
AC, a dedicated test story, or an explicit user waiver
via
approve-with-gaps(with recorded justification). Flag gaps in Step 5 and Step 8b. Theapproveoption is only available when all stories have coverage.