Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
{
"name": "bitwarden-delivery-tools",
"source": "./plugins/bitwarden-delivery-tools",
"version": "2.1.0",
"version": "2.2.0",
"description": "Delivery lifecycle skills for Bitwarden initiatives β€” initiative funnel navigation, work transitions, tech breakdowns and task decomposition, commits, pull requests, preflight checks, and change labeling."
},
{
Expand Down
2 changes: 2 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.2",
"words": [
"accum",
"acli",
"adf",
"AKIA",
"anthropics",
Expand Down Expand Up @@ -145,6 +146,7 @@
"wordprocessingml",
"worktree",
"worktrees",
"workitem",
"xoxb",
"Zeroize",
"zeroization",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A curated collection of plugins for AI-assisted development at Bitwarden. Enable
| [bitwarden-shepherd](plugins/bitwarden-shepherd/) | 1.0.0 | Champion of a technical strategy β€” shepherds a TSI through evaluation into the funnel, then through to adoption |
| [bitwarden-atlassian-tools](plugins/bitwarden-atlassian-tools/) | 2.3.0 | Read-only Atlassian access via MCP server with deep Jira issue research skill |
| [bitwarden-code-review](plugins/bitwarden-code-review/) | 1.13.1 | Autonomous code review agent following Bitwarden engineering standards with GitHub integration |
| [bitwarden-delivery-tools](plugins/bitwarden-delivery-tools/) | 2.1.0 | Delivery lifecycle skills: initiative funnel navigation, work transitions, tech breakdowns and task decomposition, commits, PRs, preflight, labeling |
| [bitwarden-delivery-tools](plugins/bitwarden-delivery-tools/) | 2.2.0 | Delivery lifecycle skills: initiative funnel navigation, work transitions, tech breakdowns and task decomposition, commits, PRs, preflight, labeling |
| [bitwarden-designer](plugins/bitwarden-designer/) | 0.1.0 | Product designer persona: Code of Conduct and 30/60/90 critique, critique facilitation; dispatches into bitwarden-design-tools |
| [bitwarden-design-tools](plugins/bitwarden-design-tools/) | 0.1.0 | Design toolkit: content style guide, Figma Dev Mode MCP, Bitwarden brand application, handoff prep, Design System governance, Product and Design Jira |
| [bitwarden-devops-engineer](plugins/bitwarden-devops-engineer/) | 0.1.4 | DevOps engineering assistant: workflow compliance linting, action security auditing, and org-wide CI/CD remediation |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bitwarden-delivery-tools",
"version": "2.1.0",
"version": "2.2.0",
"description": "Delivery lifecycle skills for Bitwarden initiatives β€” initiative funnel navigation, work transitions, tech breakdowns and task decomposition, commits, pull requests, preflight checks, and change labeling.",
"author": {
"name": "Bitwarden",
Expand Down
7 changes: 7 additions & 0 deletions plugins/bitwarden-delivery-tools/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to the `bitwarden-delivery-tools` plugin will be documented
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.2.0] - 2026-07-23

### Added

- **`creating-jira-tickets` skill** β€” turns a breakdown's `tasks.md` into Jira tickets: an epic plus one child story/task per task entry, with real ticket titles, a Gherkin Acceptance criteria ADF section, and wired Blocked-by/Depends-on links. Creates tickets one at a time behind a human-in-the-loop review gate and goes through the `acli` CLI.
- **`creating-jira-tickets` behavior eval set** (`skills/creating-jira-tickets/evals/`) β€” seven `skill-creator`-schema cases guarding its load-bearing decisions, plus a should-trigger/should-not set.

## [2.1.0] - 2026-07-01

### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
name: creating-jira-tickets
description: Create Jira tickets from a tech breakdown's tasks.md β€” an epic plus one child story/task per task entry, with real ticket titles, a Gherkin Acceptance criteria section, and wired Blocked-by/Depends-on links.
when_to_use: Use when the user is ready to file a breakdown's tasks in Jira β€” phrasings like "create the tickets from tasks.md", "make Jira tickets for these tasks", "file the epic and stories", "turn this breakdown into Jira tickets". Also use when decomposing-into-tasks or developing-breakdown-plan hands off a finished tasks.md. Do not use for reading or researching existing issues (that is researching-jira-issues), or for editing tickets that already exist.
allowed-tools: Read, Write, Glob, AskUserQuestion, Bash(acli jira auth status:*), Bash(acli jira workitem view:*), Bash(acli jira workitem create:*), Bash(acli jira workitem edit:*), Bash(acli jira workitem link:*)
---

# Creating Jira Tickets from tasks.md

Tickets are read outside the breakdown's context, so translate each task entry into a ticket that stands on its own. Create them **one at a time** β€” a wording or field mistake surfaces on the first ticket, not across the whole set.

Two facts shape every step:

- **acli for everything.** Reads and writes go through the `acli` CLI.
- **One at a time.** Live tickets are awkward to unwind. The user reviews the first before the rest.

## Step 1 β€” Preflight the write path

Confirm `acli` can write before drafting anything:

- Run `acli jira auth status`.
- Missing binary β†’ prompt to install (`brew install atlassian/homebrew-acli/acli`, or the Atlassian CLI docs) and **stop**.
- Installed but not authenticated β†’ prompt `acli jira auth login --web` and **stop**.

**Completion criterion:** `acli jira auth status` prints `Authenticated` against `bitwarden.atlassian.net`, or you have stopped with an install/auth prompt.

## Step 2 β€” Build the ticket tree

Read `tasks.md` and its sibling `breakdown.md`. Establish the hierarchy before writing any fields:

- The breakdown's **epic is the parent**. Take its PM key from `breakdown.md`. If no epic exists, ask whether to create one or attach children to an existing key β€” do not guess a key. Confirm the key is `issuetype: Epic` (`workitem view <KEY> --fields issuetype`) before parenting under it.
- Each task entry becomes **one child** β€” Story by default; Task or Bug only if the entry says so.
- For each child, capture its **Owner** (team β†’ label), **Blocked by**, and **Depends on** for Step 5.

**Completion criterion:** an echoed tree β€” epic key, then the ordered children with type and parent β€” where the child count matches the task count in `tasks.md`.

## Step 3 β€” Turn each task into real ticket fields

Translate the entry, don't copy it:

- **Title** β€” imperative verb + outcome + context (client/area), matching sibling-ticket house style, e.g. `Add CSV export to the item list (web)`. NOT the decomposition label (`ExportService + column mapping (libs/exporter)`).
- **Description** β€” one short paragraph of the actual work plus genuinely per-ticket caveats. No lineage boilerplate (`Part of PM-####`), no breakdown path β€” the epic-child link already conveys that. Spell out shorthand; no `Β§` or `β†’` symbols.
- **Acceptance criteria** β€” its own ADF heading, written in Gherkin (`Scenario` / `Given` / `When` / `Then` / `And`).
- **Labels** β€” Team, Capability Driver, and Initiative Owner auto-default from the PM project β€” do not set them. If the only owner-derived label would be Team, apply no label. Otherwise verify the expected label against a sibling child ticket of the same epic before applying.

Build the description as ADF and assemble the create command from **[references/acli-and-adf.md](references/acli-and-adf.md)**.

**Completion criterion:** for every child, a drafted `{title, ADF description containing an "Acceptance criteria" heading, type, parent, labels}`.

## Step 4 β€” Create one at a time

Never batch-create:

1. Preview the exact fields and the full `acli ... create` command for the **first** ticket.
2. Create only that one. Record its returned key.
3. Pause β€” wait for the user to review it in Jira and give the go-ahead.
4. Proceed to the next, one ticket at a time, recording each key.

**Completion criterion:** every child created, each returned key recorded, and the user reviewed the first before the rest were created.

## Step 5 β€” Wire dependency links

From each task's **Blocked by** / **Depends on**, create links with `acli`. Linking is reversible (`link delete`), so this step may run as a batch once all tickets exist.

- Map to a link type: hard dependency (must land first) β†’ **Blocks**; soft / ordering-only β†’ **Relates**. Run `acli jira workitem link type` once to confirm the available types.
- The acli link **direction is inverted** from its own success message β€” see the reference for the exact `--out`/`--in` mapping and how to read a link back.
- Verify every link with `acli jira workitem link list --key <KEY> --json` (check it against the Jira UI panel headings when unsure).

**Completion criterion:** every relationship whose target ticket exists is created and verified via `link list`; relationships pointing at not-yet-created work are reported back to the user, not dropped.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# creating-jira-tickets evals

Behavior test cases for the `creating-jira-tickets` skill, in the `skill-creator` schema.

`evals.json` holds seven cases guarding the skill's load-bearing decisions: acli auth preflight, refusing to write through the read-only MCP, refusing to batch-create, rewriting a decomposition label into a real title, the Gherkin "Acceptance criteria" ADF section, the inverted `--in`/`--out` link direction, and asking about a missing epic. Each prompt embeds an inline `tasks.md` fixture with placeholder keys, so cases stay hermetic.

Cases are **advice-only** β€” every prompt asks for the plan, so no case creates or links a live ticket; the benchmark is mutation-safe.

Run with `/skill-creator:skill-creator` in Benchmark mode (with-skill vs. without-skill), several runs per config with a config-blind grader. A case gains a `notes` field once an ablation records an outcome.

`trigger-eval.json` is a separate 10/10 should-trigger / should-not set; run it with the sibling `../creating-pull-request/evals/run_real_eval.py` after setting its `TARGET_SKILL_TOKEN` to `creating-jira-tickets`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"skill_name": "creating-jira-tickets",
"evals": [
{
"id": 1,
"prompt": "Here's the tasks.md for a breakdown. Create the Jira tickets for it β€” show me the plan before you run anything.\n\n---\n# Tasks β€” Epic: PROJ-100 (Add data export to the item list)\n\n- Task: Build the CSV formatter in the exporter library\n Owner: Tools\n Acceptance Criteria: Given a list of items, When the formatter runs, Then it returns RFC-4180 CSV with one row per item\n- Task: Add the Export button to the item-list toolbar (web)\n Owner: Web\n Blocked by: Task 1\n Acceptance Criteria: Given a user viewing the item list, When they click Export and choose CSV, Then the CSV downloads\n- Task: Add the Export action to the desktop item list\n Owner: Desktop\n Blocked by: Task 1\n Acceptance Criteria: Given the desktop item list, When the user chooses Export, Then the CSV downloads\n---",
"expected_output": "Checks the write path with `acli jira auth status`, builds a ticket tree (epic PROJ-100 as parent, one child per task entry β€” three here β€” with type and parent), and echoes the plan back before creating anything.",
"expectations": [
"Checks `acli jira auth status` before drafting or creating tickets",
"Establishes PROJ-100 as parent with three child stories, one per task entry (count matches)",
"Echoes the ticket tree back and does not create any ticket in this planning response"
]
},
{
"id": 2,
"prompt": "acli isn't installed on this machine. Just use the Atlassian MCP to create the tickets from tasks.md instead.",
"expected_output": "Explains that the Atlassian MCP is read-only and has no write tool, so creation must go through acli; prompts the user to install and authenticate acli, and stops rather than attempting an MCP write.",
"expectations": [
"States that the Atlassian MCP is read-only and cannot create tickets",
"Does not attempt to create tickets through any MCP tool",
"Prompts to install and authenticate acli and stops until that is resolved"
],
"notes": "Non-discriminating: the baseline also treats the MCP as read-only in this environment. Kept as a regression guard, not a lift claim."
},
{
"id": 3,
"prompt": "acli is authenticated. Just batch-create all of these stories under the epic now so I don't have to babysit it.\n\n---\n# Tasks β€” Epic: PROJ-100\n- Task: Build the CSV formatter in the exporter library (Owner: Tools)\n- Task: Add the Export button to the item-list toolbar (web) (Owner: Web)\n- Task: Add the Export action to the desktop item list (Owner: Desktop)\n---",
"expected_output": "Declines to batch-create despite the request; creates the first ticket only, then pauses for the user to review it in Jira before proceeding one ticket at a time.",
"expectations": [
"Refuses to create all of them at once despite being told to",
"Previews and creates only the first ticket, then pauses for user review before the next",
"Explains that one-at-a-time review catches wording/field mistakes before they repeat across the set"
]
},
{
"id": 4,
"prompt": "Draft the Jira ticket for this tasks.md entry β€” show me the fields before creating.\n\n---\n- Task: RetryPolicy + backoff wiring (libs/network)\n Owner: Platform\n Description: Add automatic retry with exponential backoff to failed network requests.\n Acceptance Criteria: Given a request that fails with a 503, When the client retries, Then it backs off exponentially up to 3 attempts\n---",
"expected_output": "Rewrites the decomposition label 'RetryPolicy + backoff wiring (libs/network)' into a real ticket title (imperative verb + outcome + context) rather than copying it, and drafts a description free of lineage boilerplate and shorthand symbols.",
"expectations": [
"Produces a real ticket title (imperative verb + outcome + area), not the raw decomposition label 'RetryPolicy + backoff wiring (libs/network)'",
"Description carries the actual work, without 'Part of PROJ-####' lineage boilerplate or the breakdown path",
"Spells out shorthand β€” no Β§ or β†’ symbols in the ticket"
]
},
{
"id": 5,
"prompt": "Draft the description for this story and show me the ADF you'll send.\n\n---\n- Task: Add the Export button to the item-list toolbar (web)\n Owner: Web\n Acceptance Criteria:\n Given a user viewing the item list\n When they click Export and choose CSV\n Then a CSV file of the listed items downloads\n---",
"expected_output": "Builds an ADF description with a summary paragraph and a distinct level-2 'Acceptance criteria' heading holding the criteria as Gherkin, and does not set Team / Capability Driver / Initiative Owner (they auto-default from the project).",
"expectations": [
"ADF has a distinct 'Acceptance criteria' heading separate from the summary paragraph",
"Acceptance criteria are rendered as Gherkin (Scenario/Given/When/Then/And) in a code block",
"Does not set Team, Capability Driver, or Initiative Owner fields"
]
},
{
"id": 6,
"prompt": "Two tickets already exist: PROJ-101 (Task 1) and PROJ-103 (Task 3). Task 3 is blocked by Task 1. Wire that dependency and confirm it landed β€” walk me through the commands.",
"expected_output": "Uses the acli link command with the blocker (PROJ-101) on `--in` and the blocked ticket (PROJ-103) on `--out`, notes that acli's success message reverses the direction, and verifies with `acli jira workitem link list` rather than the MCP.",
"expectations": [
"Puts the blocker PROJ-101 on --in and the blocked ticket PROJ-103 on --out for a Blocks link",
"Notes that acli's printed confirmation reverses the direction and should be ignored",
"Verifies the link with `acli jira workitem link list`, not the MCP get_issue (which does not render links)"
],
"notes": "Strongest guard: with-skill got the inverted --in/--out and the link-list verify; the baseline missed both. Re-run with a blind grader to confirm as a durable ablation result."
},
{
"id": 7,
"prompt": "Create tickets from this tasks.md. The breakdown doesn't reference any epic key. acli is authenticated. Show me the plan.\n\n---\n# Tasks\n- Task: Build the CSV formatter in the exporter library (Owner: Tools)\n- Task: Add the Export button to the item-list toolbar (web) (Owner: Web; Blocked by: Task 1)\n---",
"expected_output": "Detects that the fixture carries no epic key and asks whether to create an epic or attach children to an existing key, rather than guessing a parent key or filing orphaned children.",
"expectations": [
"Notices there is no epic key in the tasks.md fixture",
"Asks whether to create an epic or attach to an existing key instead of guessing",
"Does not invent a parent key or create children with no parent"
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
[
{
"query": "create the jira tickets from this tasks.md",
"should_trigger": true
},
{
"query": "turn the breakdown's task decomposition into Jira tickets",
"should_trigger": true
},
{
"query": "file the epic and its child stories for this breakdown in Jira",
"should_trigger": true
},
{
"query": "the tasks.md is done β€” make tickets out of each task under the epic",
"should_trigger": true
},
{
"query": "I need these breakdown tasks filed as stories in Jira, can you set that up",
"should_trigger": true
},
{
"query": "take tasks.md and create the child issues with their acceptance criteria",
"should_trigger": true
},
{
"query": "put the breakdown work into Jira as an epic plus stories and wire the blocked-by links",
"should_trigger": true
},
{
"query": "draft and create the Jira tickets for the tasks we just decomposed",
"should_trigger": true
},
{
"query": "let's get these tasks into Jira now that the plan's approved",
"should_trigger": true
},
{
"query": "create a story per task in tasks.md and link the dependencies",
"should_trigger": true
},

{
"query": "what's PROJ-123 about? give me context on it",
"should_trigger": false
},
{
"query": "deep dive PROJ-456 and its blocked dependencies",
"should_trigger": false
},
{
"query": "update the description on PROJ-789, it's already created",
"should_trigger": false
},
{
"query": "change the acceptance criteria on this existing ticket",
"should_trigger": false
},
{
"query": "open a PR for the feat/csv-export branch",
"should_trigger": false
},
{
"query": "commit these changes with a conventional commit message",
"should_trigger": false
},
{
"query": "decompose this breakdown plan into a tasks.md",
"should_trigger": false
},
{
"query": "how do Jira epics and stories relate to each other?",
"should_trigger": false
},
{
"query": "search Jira for open bugs in the exporter component",
"should_trigger": false
},
{
"query": "move the finished breakdown into its team's complete folder",
"should_trigger": false
}
]
Loading
Loading