jira-story-triage · v1.0 · 2026-07-23 · sha256 343fddf985f14aa0
jira-story-triage v1.0A
Immutable. This exact content is served forever at /api/v1/blob/343fddf985f14aa0.
--- name: jira-story-triage description: "Use this skill to audit a Jira backlog, sprint, or any JQL-scoped set of stories for agent-readiness — score each story against the five-question actionability bar and output a Tier A / B / C / Blocked table with complexity grouping. Triggers on \"score the backlog\", \"which tickets are ready to ship\", \"triage sprint for actionability\", \"classify PROJ backlog by tier\", \"what's agent-ready in PROJ\", \"run a backlog health audit\", \"score these stories\", \"which stories in sprint 12 can we execute\". Do NOT use for: showing team sprint status with a pick-up hand-off (use jira-team-status), creating or updating issues (use jira), turning an epic into specs (use jira-brief-intake), or fixing a defect (use jira-defect-flow)." metadata: version: "1.0" --- # Skill: jira-story-triage A read-only audit tool. Given a JQL scope, it fetches stories via the `jira` skill, evaluates each against the five-question actionability bar, and produces a Tier A / B / C / Blocked table the team can act on directly. This skill is for one-off or periodic backlog audits. For the sprint-cadence session entry point with a pick-up hand-off, use `jira-team-status`. ## Cross-skill invocation — name, not path This skill names the `jira` skill **by its `name:` field, never by path**. Install locations vary by IDE and scope. When this skill says *"via the `jira` skill: `search ...`"*, the agent uses its native skill-dispatch mechanism to invoke the skill registered under that name. ## Prerequisites Before stage 1, verify: **`jira` is installed and authenticated — a hard dependency.** Invoke: `jira: check`. - Exit 0 → proceed. - Exit 2 → the user must act. Tell them to run `credential-setup` themselves (interactive — do not run it for them), then stop. **Do not dispatch any reads into an auth failure.** ## The five-question actionability bar > A story is actionable when all five are true: > (Q1) it is a **self-contained code/config/doc change** — not discovery, design, or coordination work; > (Q2) it names a **reachable repo or file scope** so the change can be located without a follow-up meeting; > (Q3) its **acceptance criteria are checkable by diff review alone** — no "TBD", "coordinate with", "decide on", or "prototype"; > (Q4) **no human decision is needed mid-flight** — no open design question, no external approval gate that cannot be confirmed before work starts; > (Q5) it is **right-sized for one PR** — the scope is an enumerable set of files or PRs a single person or agent can produce without decomposing into sub-stories. Q5 exists because Jira stories are an old delivery-capacity allocation mechanism: a story sized for a full sprint or cross-team effort passes Q1–Q4 but still cannot be handed to an agent without being broken down first. ## Tier rubric — total function **Pre-check (runs before scoring; triggers → Blocked, skip scoring):** A story is **Blocked** when its description is empty, image-only (`!image-…!` Jira wiki markup), or its `issuetype` is a discovery artifact (Solution Design, Discovery, Spike without acceptance criteria, or equivalent). Blocked stories cannot be scored meaningfully. **Scored tiers (apply only after the pre-check passes):** | Tier | Condition | |---|---| | **A — Turnkey** | All five bar questions pass. The story can be started immediately. | | **B — Gated** | Exactly one bar question fails, AND that failure is an **external gate**: a specific named decision pending from a named person, credentials not yet provisioned but provisioning is confirmed, or an external dependency available on a specific future date. Content failures (missing repo scope, missing ACs, missing right-sizing) are **never** Tier B regardless of how many other questions pass. | | **C — Needs shaping** | Any other outcome: any content dimension fails (Q1, Q2, Q3 missing/wrong), Q4 fails with an open design question rather than a named external gate, or Q5 fails (story is too large and needs decomposition). | ## Lifecycle ### Stage 1 — Repo grounding Detect `git remote -v` in the working directory. If a URL is found, capture it as the **invocation repo** — the repo the agent is running from, not necessarily the target of every story in the backlog. If not in a git repo (or no remote configured), offer: > "Optionally supply a repo URL or name — this helps verify whether stories > reference a reachable scope. Enter to skip." Proceed with "Invocation repo: unknown" if the user declines. ### Stage 2 — Intake Accept one of: - A JQL expression (e.g. `project = PROJ AND sprint in openSprints()`) - A sprint/board scope (convert to JQL automatically: `project = PROJ AND sprint = "Sprint 12"`) - A project key alone (default to open sprints: `project = PROJ AND sprint in openSprints() AND statusCategory != Done`) For a large result set (> 100 stories), paginate using the `jira` skill's `--limit` and inform the user of the total count before scoring. ### Stage 3 — Fetch Via the `jira` skill's `search` subcommand: ``` jira: search "<JQL>" --fields "summary,description,issuetype,status,priority,labels,story_points,customfield_*" --limit 100 ``` Fetch `customfield_*` to capture story-point fields (typically `customfield_10016` on Cloud; varies by instance). If a specific story-point field is known, use it; otherwise infer from the field catalog (`jira: raw GET field`) and cache for the session. ### Stage 4 — Pre-check (runs first, short-circuits Blocked stories) For each story, check before scoring: - Description is empty or contains only `!image-…!` Jira wiki markup? → **Blocked** - `issuetype.name` matches a discovery artifact pattern (case-insensitive: "solution design", "discovery", "spike" — but only when no acceptance criteria are present)? → **Blocked** Confirm suspected image-only descriptions: if the description field appears truncated in the API response, fetch the raw content before marking Blocked. Blocked stories skip all further scoring. Mark tier = "Blocked" and reason = "empty/image-only description" or "discovery issuetype". ### Stage 5 — Score non-Blocked stories Apply each bar question using word-boundary matching (English; non-English text or unknown issuetypes fall through to "type unknown — manual review"): - **Q1**: `issuetype.name` is Story, Task, Bug, or Sub-task AND summary/description free of "define how", "explore", "assess", "design the approach", "discuss", "align with", "determine", "investigate", "look into", "coordinate with" (word-boundary match, case-insensitive). - **Q2**: Description or labels contain a repo URL, repo name, or file path pattern (e.g. `gitlab.org/…`, `github.com/…`, a recognizable path like `src/` or `.py`). - **Q3**: Description or a custom field contains text identifiable as acceptance criteria (checkbox list, "AC:", "Acceptance Criteria:", or numbered list of verifiable conditions) AND those criteria do not contain "TBD", "coordinate with", "decide on", or "prototype". - **Q4**: Summary and description free of "pending decision from", "awaiting alignment", "TBD — blocked on", or equivalent open-approval language. - **Q5**: Story-point field ≤ team threshold (default 5; fallback: description ≤ 200 words AND ≤ 5 ACs) AND no "multiple repos", "cross-team", or "multi-week" language. If a question is ambiguous (content not deterministic), mark the question as "uncertain" and note it in the "Blocking issue" column. Never invent a pass or fail where the content is genuinely unclear. ### Stage 6 — Classify Apply the tier rubric (total function): 1. If the pre-check fired → Blocked (already done in stage 4). 2. All five Q pass → Tier A. 3. Exactly one Q fails AND the failure is a named external gate → Tier B. (Content failures such as missing repo scope, missing ACs, or missing right-sizing are always Tier C regardless of how many other Qs pass.) 4. Any other combination → Tier C. ### Stage 7 — Complexity scoring (Tier A stories only) For Tier A stories, assign complexity using the following signal hierarchy: | Signal | Quick | Standard | Involved | |---|---|---|---| | Story-point field | ≤ 2 pts | 3–5 pts | > 5 pts | | Description length (fallback if points absent) | ≤ 100 words | 101–200 words | > 200 words | | AC count (secondary fallback) | ≤ 2 ACs | 3–5 ACs | > 5 ACs | Apply signals in order: story-point field (primary), then description length, then AC count. If all signals are unavailable, mark complexity as "unknown". ### Stage 8 — Output Header: ``` Invocation repo: <URL> (detected) [or: Invocation repo: unknown] Triage scope: <JQL> Stories evaluated: <total> ``` Markdown table, sorted A → B → C → Blocked. **Within the Tier A block, rows are sub-grouped by complexity with a sub-header per band (Quick first, then Standard, then Involved):** | Key | Summary | Tier | Complexity | Blocking issue / gate | Q5 right-sized? | |---|---|---|---|---|---| | PROJ-101 | Add dotenv support to dashboard | A | Quick | — | Yes | | PROJ-103 | Rename metric key in config | A | Quick | — | Yes | | PROJ-107 | Retrofit telemetry onto renamed pack | A | Standard | — | Yes | | PROJ-112 | Npm scope rename | B | — | Decision: new scope name needed from @owner | Yes | | PROJ-99 | Update the agents | C | — | Q1: vague summary; Q2: no repo named; Q3: no ACs | Unknown | | PROJ-106 | !image-agent-map.png! | Blocked | — | Image-only description — no text content | — | Footer: ``` Agent-ready: <n> (Quick: <q>, Standard: <s>, Involved: <i>) Gated: <g> Need shaping: <c> Blocked: <b> ``` ## Don't - Don't write any Jira verb other than `search` and `get-issue` (for the image-content confirmation check). This skill is read-only. - Don't rewrite a story's content — surface what's wrong; rewriting is for the `jira-team-status` shaping hand-off (user-initiated, explicit consent). - Don't reference local repo files or the local workspace queue. - Don't hardcode a sibling skill by path; invoke by name. - Don't classify ambiguous content as a definitive pass or fail — mark it "uncertain" and surface the ambiguity in the output. ## Edge cases - **Story-point field absent or zero.** Fall back to description length + AC count. Note "points unavailable — complexity estimated from description" in the complexity cell. - **Non-English backlog.** Q1/Q4 keyword matching will miss non-English signals. Note this limitation in the output header; proceed with scoring where possible. - **Custom issuetype not in the known list.** Mark Q1 as "type unknown — manual review"; do not force-classify as pass or Blocked. - **Large sprint (> 100 stories).** Paginate via the `jira` skill's `--limit` with multiple calls; inform the user of the total count and page count before beginning. ## Examples See [`references/examples.md`](references/examples.md).