Turns rough input into structured Jira work. Two modes — single-ticket mode turns a bug description, meeting notes, Slack thread, incident writeup, or a few sentences into one fully-structured Jira ticket; decomposition mode turns a rough requirements doc or product brief with multiple asks and open questions into several linked Jira stories with business/technical context, an open-questions map, a traceability matrix, and a self-contained HTML dashboard for exploring gaps. Trigger on "toJira...
Scanned 9/6/2026
Install to Claude Code
npx -y skills add kirti/jira-ticket-builder-skill --skill skill --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Skill?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/kirti-skill)More formats (shields.io, HTML) on the badges page.
---
name: jira-ticket-builder
description: Turns rough input into structured Jira work. Two modes — single-ticket mode turns a bug description, meeting notes, Slack thread, incident writeup, or a few sentences into one fully-structured Jira ticket; decomposition mode turns a rough requirements doc or product brief with multiple asks and open questions into several linked Jira stories with business/technical context, an open-questions map, a traceability matrix, and a self-contained HTML dashboard for exploring gaps. Trigger on "toJira", "jira ticket", "make this a ticket", "file a bug", "write this up as a story/spike/task", "break this down into stories", or when rough notes/a requirements doc are pasted with a request for tickets, even without the word "Jira." Also trigger in a codebase (Claude Code) when the user points at a bug/TODO and wants it ticketed. Single-ticket mode has quick and full (enterprise) variants, adapted by issue type (Bug, Story, Task, Spike, Tech Debt, Security, Incident).
---
# Jira Ticket Builder
Converts rough input into a structured, ready-to-paste Jira ticket. Built around the pipeline:
```
ROUGH INPUT → Understand Input → Extract Facts → Fill Missing Data / Ask →
Generate Ticket → Validate → Jira Ticket
```
## Step 0 — Single ticket vs. decomposition
Before running the single-ticket pipeline below, check the input's shape:
- **Single ticket**: one bug, one feature ask, one clear unit of work → proceed with Steps 1-5 as below.
- **Decomposition**: a rough requirements document — meeting notes, a product brief, an email
thread, a spec with multiple asks and open questions bundled together — where a single ticket
would be too large or would hide independently-shippable pieces → use **Decomposition Mode**
below instead of Steps 1-5.
Signal for decomposition mode: multiple distinct capabilities mentioned, a "Questions:" section,
or the user says things like "break this down," "turn this into stories," or pastes a document
rather than a single ask.
---
## Decomposition Mode
For a rough requirements document that needs to become multiple linked Jira stories with full
traceability and an explorable dashboard.
### D1 — Analyze the document
Read the whole document first. Extract, without inventing:
- **Business context** — objectives, actors (who's involved), business rules, and the business
flow (actor → action → system, as an ordered sequence if the doc describes a process). Where a
step has a UI screen or a callable API/system, note it (`ui_screen`/`api`) — this is what lets
the Customer Journey diagram show the full stack per step, not just the business narrative.
- **Business requirements** — the business objective/problem/value being addressed
- **Functional requirements** — what the system must do
- **Non-functional requirements** — performance, security, accessibility, compliance
- **Ambiguities** — anything incomplete, contradictory, vague, or missing acceptance
criteria/technical decisions
Mark every requirement, objective, and business rule `confidence: "confirmed"` (stated in the
doc) or `"inferred"` (you concluded it from context) — never leave this implicit.
Never silently invent a requirement. If the document doesn't say it, it's not a requirement —
it's either an assumption (mark it) or an open question (mark it, and mark whether the user
stated it or you identified the gap).
### D2 — Decompose into stories
Do not create one giant story. Split into logical, independently-understandable stories —
typical categories: business capability, UI, backend/API, integration, data, security,
validation, audit, monitoring, testing, CI/CD, technical enablement. Each story:
- Gets a unique sequential ID (`STORY-001`, `STORY-002`, ...)
- Is independently testable and understandable on its own
- Must have at least one `source_requirement_ids` entry — no orphan stories
- Uses the `type` field to distinguish Story / Technical Story / Spike / Enabler / Bug / Task
- Includes a short `decomposition_rationale` — why this is its own story rather than folded into
another one. This is what lets a reviewer sanity-check the split, not just accept it.
- Fill `technical_context` per story: affected systems, APIs (as method/path/request/response/auth,
not just a name), data, security, a `ui_spec` (or `"n/a"` if no UI surface) including
`navigates_to` for any screen-to-screen transitions (this drives the UI Flow diagram), `testing`
(unit/integration/api/e2e as short lists), and `cicd` notes if the story has deployment-specific
needs. Leave individual fields as `"none identified"` rather than fabricating detail.
- Distinguish `dependencies` by relationship: `depends_on`, `blocks`, or `relates_to` — "STORY-002
depends on STORY-001" is a different fact than "STORY-002 relates to STORY-004" and the portal
renders them differently.
- Give an honest `completeness_pct` — a story with unresolved open questions or "none identified"
technical context across the board should not read as 100% complete.
Prefer several small, independently deliverable stories over one large one.
### D3 — Map open questions, decisions, and risks
Every question in the source doc gets mapped to the story/stories it affects, with an area
(Business/UI/Backend/Security/NFR/Data/CI-CD), a **severity** (Critical/High/Medium/Low — how much
it blocks implementation), an **owner** (`"Unassigned"` unless the doc names one — never invent a
name), and an impact description. Additionally, identify questions that weren't explicitly written
but are necessary to implement the requirement (e.g. no performance target stated but response
time clearly matters) — mark these `origin: "ai_identified"` and never present them as if the user
asked them.
**Decisions** and **risks** are opt-in — only emit them when the source doc actually shows a
decision being made/needed, or a specific, nameable risk. Don't pad these lists with generic
boilerplate to look thorough; an empty or short list is more honest than filler.
### D4 — Build traceability and architecture
For every requirement, list which story/stories cover it, the source excerpt it came from, and
whether it's fully covered. A requirement with no story covering it is a gap — surface it, don't
hide it. Traceability coverage % = covered requirements / total requirements.
Build a lightweight `architecture` object: the request flow (e.g. User → UI → API → Service →
Data), a components list (name/type/description), and structured integration points
(`{from, to, label, type}`, with `from`/`to` matching names in `flow` or `components` exactly).
Keep this structural and factual — this skill renders it as a real diagram from the data, so
consistency between names matters, but you're still not hand-drawing a layout, just supplying the
facts.
### D5 — Quality gate (run before output)
**Run `assets/quality_gate.py` against the assembled data file — don't re-derive these checks
ad hoc.** This exact class of bug (an open question's `story_ids` pointing at a story that
doesn't reciprocate in its own `open_question_ids`) has appeared on every decomposition tested
so far — a script catches it reliably where re-implementing the check freehand each time doesn't.
```
python3 assets/quality_gate.py <data_json_path>
```
It checks: every requirement traced, every story has acceptance criteria, open-question/story
cross-links are reciprocal, every question has severity + owner, every story has a source
requirement link, every requirement has a confidence marking, no story has fully blank
technical_context, and no architecture integration_point references a name absent from
`flow`/`components`. Exits non-zero on any failure — fix the data and re-run before moving to D6,
don't generate the portal on a failing gate.
### D6 — Build the data + portal
**Build this in separate steps, one file at a time — never hand-author one giant single-shot
blob.** A large decomposition (10+ stories, many questions/risks/decisions) embedded into one
huge HTML text block, or ten large pages typed out by hand in one pass, is exactly the kind of
output that stalls or gets truncated.
1. **Write the JSON data to its own file first** (e.g. `/tmp/decomposition-data.json`), not
inline in any HTML. If the source doc is large, build this in chunks across multiple tool
calls — e.g. write `business_requirements`/`functional_requirements`/
`non_functional_requirements`/business context first, then append `stories` (in batches if
there are many), then `open_questions`/`assumptions`/`decisions`/`risks`/`architecture`/
`traceability`/`readiness`. Use Python's `json` module to assemble and validate
(`json.load`) rather than hand-typing one huge JSON literal.
2. **Generate the portal as linked HTML pages, not one page.** Copy
`assets/portal-page-template.html` and `assets/build_portal.py` into the workspace as-is —
don't retype them. Run:
```
python3 build_portal.py <template_path> <data_json_path> <output_dir>
```
This produces `index.html` (Overview), `business-context.html` (includes a Business Flow
diagram), `customer-journey.html` (swimlane diagram connecting customer action → UI screen →
backend call per step), `requirements.html`, `stories.html`, `open-questions.html`,
`traceability.html`, `architecture.html` (includes an Architecture diagram), `ui-flow.html`
(screen-to-screen navigation diagram), `assumptions.html`, `decisions.html`, `risks.html` —
one file per iteration inside the script, which is naturally chunked rather than one massive
write. Each page embeds the full dataset and links to the others via its sidebar nav (real
`<a href>` page loads, not a JS view-switcher) — the sidebar nav present on every page *is* the
map connecting them, so there's no separate index/map file to build beyond `index.html` itself.
3. **Never write literal `</script>` text anywhere inside a script tag's own content**
(including comments) — the HTML parser closes the tag on that substring regardless of context
and silently breaks the page. If you need to reference a script tag in a comment, don't write
the literal closing-tag substring.
4. Spot-check at least `index.html` and `stories.html` render correctly (well-formed HTML, JSON
parses, nav links resolve to the right filenames) before presenting — don't hand over
unverified files.
5. Also write the stories out as markdown (one file, using `assets/story-template.md`'s structure
per story, or a condensed per-story block) — the portal is for exploring, the markdown is for
pasting into Jira. Build this incrementally per story for large decompositions too.
6. **Zip the 12 HTML pages into a single archive before presenting them** — do not present the
loose HTML files individually. The pages link to each other with relative hrefs
(`business-context.html`, `stories.html`, etc.), and `present_files` serves each presented file
as an isolated resource, not as siblings in a shared directory — so a person clicking the
sidebar nav on a file opened straight from a `present_files` card will find most links don't
go anywhere, even though the pages themselves are correct. Zipping means the person downloads
once, extracts to one folder, and opens `index.html` from there, where the relative links
resolve normally because the files are genuinely sitting next to each other on disk. Use
Python's `zipfile` module:
```python
import zipfile, os
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as z:
for f in sorted(os.listdir(portal_dir)):
z.write(os.path.join(portal_dir, f), f)
```
Present the `.zip` (plus the markdown file) via `present_files`, and say explicitly in your
response that the person needs to extract it before opening `index.html` — don't let them
discover that by hitting a dead link.
7. Save the zip and the markdown to the outputs directory and present them, leading with the zip
since that's the entry point.
Flag the quality gate results and the 3 most important gaps/open questions in your written
response — don't make the user hunt through the portal to find out something's missing.
---
## Single-Ticket Mode
### Step 1 — Understand the input
Input may come from:
- Pasted/typed text (bug reports, feature asks, one-liners)
- Uploaded files (meeting notes, Slack exports, incident postmortems) — read these fully before extracting facts
- Code context (Claude Code use) — if the user points at a bug, error, or TODO in a repo, read the
surrounding code/tests/commit history for facts before asking the user anything
If the source material is ambiguous about what's actually being requested (a bug fix vs. a bigger
redesign, for instance), make the most reasonable read and state the assumption rather than
stalling on it.
### Step 2 — Extract facts
Pull out, explicitly, before writing anything:
- What happened / what's being asked for
- Who's affected (users, internal teams, systems)
- Component/service involved
- Business or user impact
- Urgency/priority signals
- Issue type signal (bug report language → Bug; "we should build..." → Story; "not sure how to
approach X" → Spike; "this is getting hard to maintain" → Tech Debt; production-down language →
Incident)
### Step 3 — Decide mode and issue type, fill gaps
**Mode — ask if not specified:**
- **Quick mode**: short ticket, minimal sections, fast to produce. Good default when the user
gives a short prompt and doesn't ask for depth.
- **Full mode**: the complete enterprise template. Good default when the user gives detailed
input, mentions "enterprise," "full," "detailed," or when the ticket is for a Bug, Incident, or
Security issue (these benefit from the full template's rigor even on a light ask — offer to
default to full mode for these types and let the user downgrade to quick if they prefer).
If genuinely unclear which mode fits, ask once rather than guessing — this is a case where
getting it wrong wastes a full ticket-generation pass.
**Issue type — infer from context**, but confirm if truly ambiguous.
**Fill missing data**: For anything not stated or inferable, do not invent specifics (fake owners,
fake ticket links, fake metrics). Either:
- Leave a clearly marked placeholder (`TBD`, `Not specified`), or
- Note it under "Missing Information" in the AI-Generated Information section (full mode) or
"Notes / Open Questions" (quick mode)
Ask the user directly only when a single missing fact would materially change the ticket's
shape (e.g., "is this production or staging?" when severity depends on it). Otherwise, proceed
and flag the gap rather than blocking on it.
### Step 4 — Generate the ticket
- **Quick mode**: use `assets/quick-template.md` as-is (drop "Steps to Reproduce" for
Story/Task/Spike/Tech Debt per that file's own note).
- **Full mode, Story**: use `assets/story-template.md` — a dedicated template built around user
value (As a/I want/So that, current vs. desired state, demoable acceptance criteria, success
metrics), not the bug-mechanics template with sections trimmed out. Do not use
`full-template.md` for stories.
- **Full mode, everything else (Bug, Task, Spike, Tech Debt, Security, Incident)**: use
`assets/full-template.md`, then adapt sections per issue type using
`references/section-guide.md` — read that file before writing a full-mode ticket for anything
other than a plain Bug, since the right sections to keep/trim/reframe differ by type.
Fill every section with real content extracted or reasonably inferred from the input — never
leave the template's own placeholder text (`...`, `Bug / Story / Task...`) unresolved in the
output. Pick specific values.
### Step 5 — Validate before returning
Check the draft against:
- **Title**: specific and scannable, not generic ("Fix login failure after password reset", not
"Login bug")
- **Acceptance Criteria**: testable, in Given/When/Then form where applicable, actually cover the
reported problem
- **Priority/Severity**: consistent with the stated impact (don't mark something Critical off a
vague description, don't mark something Low if it says "production users are locked out")
- **Duplicates/internal consistency**: summary, description, and acceptance criteria all describe
the same problem — no drift between sections
- **AI-Generated Information / Notes section is present and honest** — this is not optional
boilerplate; it's the section that tells the human reviewer what to double-check
### Output
Full-mode tickets are substantial documents — create them as a markdown file
(`/mnt/user-data/outputs/`) and present it, don't paste 300+ lines inline. Quick-mode tickets are
short enough to return inline in the conversation unless the user asks for a file.
If working inside Claude Code / a repo, follow the same steps but write the ticket file wherever
the user indicates (e.g. alongside an issue template in the repo, or just print it for them to
copy into Jira) — there's no separate IDE-specific ticket logic, only a different delivery
location.
End by briefly flagging the 2-3 things most worth a human double-checking before filing —
don't just hand over the ticket silently.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!