Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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