@groupby/ai-dev 0.5.16 → 0.5.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/package.json +1 -1
  2. package/teams/firstspirit-caas/mcp/jira-tools.py +2122 -0
  3. package/teams/firstspirit-caas/mcp/test_bamboo_artifacts.py +315 -0
  4. package/teams/firstspirit-caas/mcp/test_jira_links.py +192 -0
  5. package/teams/firstspirit-caas/mcp/test_update_jira_ticket.py +161 -0
  6. package/teams/firstspirit-caas/resources/mcp-setup.md +57 -0
  7. package/teams/firstspirit-caas/skills/chronicle/SKILL.md +105 -0
  8. package/teams/firstspirit-caas/skills/create-jira-ticket/SKILL.md +183 -0
  9. package/teams/firstspirit-caas/skills/get-jira-ticket/SKILL.md +125 -0
  10. package/teams/firstspirit-caas/skills/handle-red-cve-plan/SKILL.md +316 -0
  11. package/teams/firstspirit-caas/skills/handle-red-cve-plan/references/suppression.md +79 -0
  12. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/gen_suppression.py +116 -0
  13. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/parse_json_report.py +183 -0
  14. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/parse_report.py +255 -0
  15. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/test_gen_suppression.py +171 -0
  16. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/test_parse_json_report.py +244 -0
  17. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/test_parse_report.py +464 -0
  18. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/testdata/sample-report.html +39 -0
  19. package/teams/firstspirit-caas/skills/handle-red-cve-plan/scripts/testdata/sample-report.json +76 -0
  20. package/teams/firstspirit-caas/skills/handle-weekly-cve-plans/SKILL.md +238 -0
  21. package/teams/firstspirit-caas/skills/retrospect/SKILL.md +94 -0
  22. package/teams/firstspirit-caas/skills/retrospect/extract_prompts.py +392 -0
  23. package/teams/firstspirit-caas/skills/review/SKILL.md +131 -0
  24. package/teams/firstspirit-caas/skills/review-finalize/SKILL.md +103 -0
  25. package/teams/firstspirit-caas/skills/specify/SKILL.md +239 -0
  26. package/teams/firstspirit-caas/skills/summarise-for-jira-comment/SKILL.md +162 -0
  27. package/teams/firstspirit-caas/skills/write-releasenotes/SKILL.md +177 -0
@@ -0,0 +1,239 @@
1
+ ---
2
+ name: specify
3
+ description: Use when the user asks to specify, flesh out, or write a spec for an existing JIRA ticket — phrases like "specify this ticket", "flesh out HP-1234", "write a spec for this", "specify HP-1234 focus on backend". Triggers on requests to enrich an existing ticket's description in place.
4
+ ---
5
+
6
+ # Specify
7
+
8
+ ## Overview
9
+
10
+ Turns a vague or incomplete JIRA ticket into a well-formed, lightweight spec by gathering evidence from all available sources, running a brainstorming-style clarification loop to fill any remaining gaps, and updating the ticket description via `mcp__plugin_planetexpress_jira-tools__update_jira_ticket`.
11
+
12
+ **Core principle:** The description is the *why* and the *what*. Code, file paths, class names, mechanical steps, and counts are excluded by default — included only when the work *is specifically about that thing*. Length follows scope — be concise; don't pad, don't artificially compress.
13
+
14
+ **Second principle:** If the draft spec adds nothing the original didn't already say, the ticket is already specified — emit the canonical short message instead of rewording in place. See Step 5.
15
+
16
+ ## When to use
17
+
18
+ - User asks to specify / flesh out / write a spec for an existing JIRA ticket
19
+ - User says "specify this ticket", "flesh out HP-1234", "write a spec for this", or similar
20
+ - User invokes the skill with optional constraints: "specify HP-1234 focus on backend API"
21
+
22
+ ## When NOT to use
23
+
24
+ - User wants to create a new ticket from scratch — use `create-jira-ticket`
25
+ - User wants to post a summary of completed work — use `summarise-for-jira-comment`
26
+ - User wants to update multiple tickets in one go — no tool supports that; handle individually
27
+
28
+ ## Workflow
29
+
30
+ ### 1. Identify the ticket key
31
+
32
+ - Default: parse `[A-Z]+-\d+` from the current branch name (e.g. `feature/HP-1615-spring-boot-4` → `HP-1615`)
33
+ - Override: explicit key in user message or constraints
34
+ - Unresolvable or ambiguous: ask before proceeding
35
+
36
+ ### 2. Fetch evidence
37
+
38
+ Gather before asking any questions:
39
+ - `mcp__plugin_planetexpress_jira-tools__get_jira_ticket` — current description, comments, status, and **`issuetype`** (drives the description shape — see "Description format" below)
40
+ - `mcp__plugin_planetexpress_jira-tools__get_jira_dev_info` — linked PRs, branches, commits
41
+ - Relevant codebase reads — only what the ticket context implies; do not scan the whole codebase to "be thorough"
42
+
43
+ **Capture the issuetype** from the fetched ticket: `Bug` selects the bug shape; anything else (`Story`, `Task`, `Sub-task`, `Improvement`, `Epic`, or unknown) selects the story shape.
44
+
45
+ **Extract the true original description** from the fetched description:
46
+ - If the description contains the marker `----\n*Original description:*`, the text *below* that marker is the original (the ticket was already processed by `specify`). Use that as the original.
47
+ - Otherwise, the full current description is the original.
48
+ - Store this as `ORIGINAL` — it will be preserved verbatim in the final update.
49
+
50
+ ### 3. Draft spec + identify follow-on candidates
51
+
52
+ Internally draft the description in the shape that matches the ticket's `issuetype` (see "Description format" below — Story shape uses `*To achieve:*` / `*I want:*`; Bug shape uses `*Bug:*` / `*Expected behaviour:*`). Simultaneously identify follow-on ticket candidates: out-of-scope items, unrelated bugs found while reading code, prerequisite work that belongs in a separate ticket.
53
+
54
+ ### 4. Mandatory brainstorming gate
55
+
56
+ **Always** show the draft and ask the user using `AskUserQuestion` before proceeding — this step is **never skipped**.
57
+
58
+ First, **show the current draft spec** to the user (verbatim, exactly as it would appear in JIRA — apply the composite format from Step 7 if ORIGINAL is non-empty). Then ask:
59
+
60
+ > "Is the draft spec ready for review, or should we first run `superpowers:brainstorming` to explore it further?"
61
+
62
+ Options to present:
63
+ - **Proceed to review** — continue to step 5 (novelty check) and then spec approval
64
+ - **Run brainstorming** — invoke `superpowers:brainstorming` with the fetched ticket and current draft as context, then re-draft (return to step 3) and re-ask this gate
65
+
66
+ When invoking `superpowers:brainstorming`, pass `args: "skip local spec file — output is JIRA wiki markup, not docs/superpowers/specs/"` so the constraint is explicit.
67
+
68
+ **This gate is not optional.** Do not skip it even when evidence seems complete, even when the user provided constraints up-front, and even when the ticket already looks well-formed.
69
+
70
+ ### 5. Novelty check — does the draft actually add anything?
71
+
72
+ Hold the draft side-by-side with `ORIGINAL`. The draft is **novel** only if it contributes information not already present in `ORIGINAL` (including its comments/dev info you promoted in):
73
+
74
+ - surfaces a *why* the original leaves implicit
75
+ - captures non-obvious gotchas or constraints the original omits
76
+ - resolves ambiguity raised during clarification (brainstorming or user-supplied constraints)
77
+ - promotes information from comments, linked PRs, or code reads into the description so the assignee doesn't have to dig
78
+
79
+ The draft is **not novel** when it only:
80
+
81
+ - reorders, rephrases, condenses, or restructures the same points
82
+ - changes formatting (bullets ↔ prose, header layout) without new content
83
+ - shortens the original purely for brevity
84
+
85
+ If the draft is **not novel**, output exactly:
86
+
87
+ > Ticket is already specified.
88
+
89
+ Then stop the workflow. Do not present a draft. Do not call `update_jira_ticket`. If genuine follow-on candidates were identified in Step 3 (e.g. unrelated bugs found while reading code), mention them in a single short follow-up sentence and offer to file them; otherwise end the response.
90
+
91
+ If the draft **is novel**, continue to Step 6.
92
+
93
+ ### 6. Present proposed follow-on tickets (before the spec)
94
+
95
+ If follow-on candidates exist, present them as a numbered list **before** showing the spec draft:
96
+
97
+ ```
98
+ Proposed follow-on tickets:
99
+ 1. [Story] "Extract auth middleware into shared module" — currently bundled in this ticket but is a reusable piece with independent value
100
+ 2. [Bug] "Fix null handling in UserService#resolve" — discovered while reading the code; unrelated to this ticket's goal
101
+ ```
102
+
103
+ Ask the user which to keep (or none). Chosen follow-ons inform the spec's out-of-scope line. If no candidates exist, skip this step entirely.
104
+
105
+ ### 7. Present spec for approval
106
+
107
+ Show the exact content that will be written to JIRA, verbatim. The description is a composite: the new spec on top, then the original preserved below a separator (if there was an original):
108
+
109
+ **If ORIGINAL is non-empty:**
110
+ ```
111
+ <new spec in Jira wiki markup>
112
+
113
+ &nbsp;
114
+
115
+ &nbsp;
116
+
117
+ &nbsp;
118
+
119
+ ----
120
+ *Original description:*
121
+ <ORIGINAL verbatim>
122
+ ```
123
+
124
+ The three `&nbsp;` lines (each separated from its neighbours by a real blank line) are deliberate. Jira's wiki-markup renderer collapses consecutive *empty* blank lines into a single paragraph break, so naïvely writing three `\n` characters in a row produces no extra visible space. Each `&nbsp;` is a non-empty paragraph, which Jira *does* render, giving three visible empty rows above the `----` horizontal rule. Do not omit them and do not replace them with bare blank lines.
125
+
126
+ **If ORIGINAL is empty / "No description":** show only the new spec (nothing to preserve).
127
+
128
+ Present this composite to the user exactly as it will appear in JIRA, then end with:
129
+
130
+ > Reply 'update', 'yes, update', or 'apply it' to apply to \<KEY\>, or give edits.
131
+
132
+ ### 8. Strict approval gate
133
+
134
+ - Affirmative-and-explicit ("update", "yes, update", "apply it") → proceed
135
+ - Edits ("shorter", "drop that bullet", "add context about X") → revise the spec section only; keep the `ORIGINAL` section unchanged; re-present the full composite verbatim, wait again
136
+ - Anything else (silence, questions, "looks good") → do **not** update; treat as edits or a question
137
+
138
+ ### 9. Update the ticket
139
+
140
+ Construct the final description exactly as shown in the Step 7 composite (spec + separator + original, or spec only if no original). Pass this to `mcp__plugin_planetexpress_jira-tools__update_jira_ticket`. Report the returned ticket link in chat.
141
+
142
+ ### 10. Chain to `create-jira-ticket`
143
+
144
+ If no follow-on tickets were chosen (or Step 6 was skipped), stop here. Otherwise, for each chosen follow-on in sequence, invoke the `create-jira-ticket` skill to draft and file the ticket.
145
+
146
+ ## Description format
147
+
148
+ The shape follows the ticket's **`issuetype`** (captured in Step 2):
149
+
150
+ - `Bug` → **bug shape** below
151
+ - everything else (`Story`, `Task`, `Sub-task`, `Improvement`, `Epic`, or unknown) → **story shape** below
152
+
153
+ ### Story shape — for Story / Task / Sub-task / Improvement / Epic / unknown
154
+
155
+ ```
156
+ *To achieve:*
157
+ <1–3 sentences describing the goal and motivation — the *why*. Drop in the
158
+ concrete observations that justify the work (numbers, examples) when they
159
+ sharpen the case.>
160
+
161
+ *I want:*
162
+ <1–2 sentences in user-story voice describing what should happen — the *what*.
163
+ "I want X so that Y" is fine and idiomatic here.>
164
+
165
+ *Additional:*
166
+ - <non-obvious constraint, gotcha, or note>
167
+ - <only include this section when there is something genuinely non-obvious;
168
+ otherwise omit it entirely>
169
+ ```
170
+
171
+ ### Bug shape — for Bug
172
+
173
+ ```
174
+ *Bug:*
175
+ <1–3 sentences describing the observed wrong behaviour. Include the trigger or
176
+ repro context when it isn't self-evident from the summary.>
177
+
178
+ *Expected behaviour:*
179
+ <1–2 sentences describing what should happen instead.>
180
+
181
+ *Additional:*
182
+ - <repro detail, affected environment, related observation, or scope note>
183
+ - <only include this section when something is genuinely non-obvious; omit if
184
+ the bug/expected pair already says everything that matters>
185
+ ```
186
+
187
+ ### Rules common to both shapes
188
+
189
+ - **Markup:** Jira wiki markup. Use `*bold*` for the section labels above, `-` for bullets, `_italics_` and `{{monospace}}` only when they earn their place. No fenced code blocks unless code is genuinely the point of the ticket.
190
+ - **Voice:** factual and concrete. First-person ("I want…") is correct inside the `*I want:*` section; elsewhere prefer neutral. Avoid corporate filler.
191
+ - **No extra headers:** no `Scope` / `Out of scope` / `Acceptance criteria` / `Risks` / `Reference` sections. No estimates, no counts.
192
+ - **Out-of-scope line:** if chosen follow-ons make something explicitly out of scope, a single line inside `*Additional:*` suffices: `- Out of scope: <what> — tracked in [proposed ticket summary].`
193
+ - **Length:** follows scope. Be concise; don't pad and don't artificially compress. A two-line ticket and a fifteen-line ticket can both be correct — the test is whether every sentence earns its place.
194
+
195
+ ## Strong defaults — exclude unless they are the actual point of the ticket
196
+
197
+ - Code blocks or inline code
198
+ - File paths, class / method / function names
199
+ - Counts (file counts, import counts, line counts)
200
+ - Mechanical sub-tasks ("rename X → Y", "drop annotation Z")
201
+ - Acceptance criteria, out-of-scope sections, risk lists
202
+ - Time / effort estimates
203
+
204
+ **Exception clause:** include any of the above when the work *is specifically about that thing*.
205
+
206
+ ## Edge cases
207
+
208
+ | Situation | Behaviour |
209
+ |---|---|
210
+ | No ticket key resolvable | Ask the user; do not guess |
211
+ | Multiple ticket keys in branch name | Ask which one; do not pick |
212
+ | `get_jira_ticket` returns 404 | Confirm key with user before continuing |
213
+ | Evidence already fully answers why/what/notes | Draft the spec, then still run the mandatory brainstorming gate (Step 4) — the user decides whether to invoke brainstorming |
214
+ | User passed constraints at invocation | Treat as pre-filled answers; still ask the mandatory gate — brainstorming may ask fewer questions if chosen |
215
+ | No follow-on candidates | Skip step 6 entirely |
216
+ | Ticket has no existing description | No original to preserve; write spec only, no separator section. Novelty check still applies — but with empty ORIGINAL, any coherent spec is novel by definition. |
217
+ | Ticket description already has the `----\n*Original description:*` marker | Extract text below marker as ORIGINAL; replace only the spec above the separator |
218
+ | `issuetype` is `Bug` | Use the bug shape (`*Bug:*` / `*Expected behaviour:*`). |
219
+ | `issuetype` is anything else, missing, or `Unknown` | Use the story shape (`*To achieve:*` / `*I want:*`). Don't ask. |
220
+ | Ticket type strongly mismatches its actual content (e.g. a "Story" that describes a bug) | Follow the `issuetype` field — it is the source of truth for format. If the mismatch is glaring, mention it in the chat once but still format by issuetype. |
221
+ | Draft only rephrases / restructures the original — no new content | Output exactly `Ticket is already specified.` Do not present a draft, do not call `update_jira_ticket`. |
222
+ | Draft contributes one small clarification, otherwise rephrases | Still novel — keep that clarification and proceed. The novelty bar is "adds something", not "adds a lot". |
223
+ | `update_jira_ticket` returns an error | Surface verbatim; do not retry silently or claim success |
224
+ | User says "update it" referring to a draft already in chat | Confirm that draft is the one to apply, re-present verbatim, wait for explicit "update" |
225
+
226
+ ## Red flags — STOP and reconsider
227
+
228
+ | Thought | Reality |
229
+ |---|---|
230
+ | "I should list every affected file" | The assignee greps the codebase. The description is the *why*, not the *where*. |
231
+ | "Acceptance criteria will help reviewers" | Most tickets don't need them. The *what* already implies done. |
232
+ | "Counts make scope concrete" | Counts age fast and add no decision value. Drop them. |
233
+ | "Let me include mechanical steps so the assignee can follow along" | A bullet list of mechanical steps is a plan. Plans go in `./.claude/plans/`, not JIRA. |
234
+ | "User said 'looks good' — that's approval" | Strict gate: needs explicit "update" / "yes, update" / "apply it". Anything else → wait. |
235
+ | "The description is long because the work is genuinely complex" | Long usually means plan-leakage. If the length is earned by scope, keep it; if every other sentence could be cut without losing meaning, cut. |
236
+ | "I'll just tighten the existing description and that counts as specifying" | No. Tightening without adding new information is the "already specified" case — output `Ticket is already specified.` and stop. |
237
+ | "The original is verbose, so my shorter version must be an improvement" | Brevity isn't novelty. If the assignee learns nothing new from your version, don't replace the original. |
238
+ | "I should write the brainstorming output to a local spec file" | No. The specify skill skips the local file. Format the approved design as JIRA wiki markup directly. |
239
+ | "Evidence is complete — I can skip the brainstorming gate" | The mandatory gate (Step 4) is never skipped. Always show the draft first, then ask the user via `AskUserQuestion`. |
@@ -0,0 +1,162 @@
1
+ ---
2
+ name: summarise-for-jira-comment
3
+ description: Use when the user asks for a JIRA ticket summary to post as a comment, or says things like "summarise the ticket", "post a summary on HP-1234", "wrap up this ticket". Triggers on requests to produce a high-level recap of work done on a ticket and post it back to JIRA as a comment.
4
+ ---
5
+
6
+ # Summarise for JIRA Comment
7
+
8
+ ## Overview
9
+
10
+ Drafts a high-level summary of the work done on a JIRA ticket from git evidence, presents it for explicit approval, and posts it as a JIRA comment.
11
+
12
+ **Core principle:** Git is the evidence. The comment is the high-level recap, not a code walkthrough. Strong defaults exclude code, file paths, and identifiers — exceptions only when those *are* the point of the ticket.
13
+
14
+ ## When to use
15
+
16
+ - The user asks to summarise a ticket, post a summary, wrap up a ticket, or similar
17
+ - A ticket key is parseable from the current branch, or the user provided one
18
+ - There is committed work on the branch (or an explicit scope override)
19
+
20
+ ## When NOT to use
21
+
22
+ - The user wants the summary in chat only, not posted to JIRA — produce it directly without this skill
23
+ - The branch is `master`/`main` with no explicit ticket + scope override
24
+ - The user wants a per-commit changelog or release notes — different artifact
25
+
26
+ ## Workflow
27
+
28
+ **Authority hierarchy: git > user input > ticket.** Higher always wins.
29
+
30
+ 1. **Identify the ticket key**
31
+ - Default: parse `[A-Z]+-\d+` from the current branch name (e.g., `feature/HP-1615-spring-boot-4` → `HP-1615`)
32
+ - Override: explicit key the user provided in their message
33
+ - Multiple keys in branch name, or none resolvable: ask the user
34
+
35
+ 2. **Identify the scope**
36
+ - Run `git fetch origin` first so `origin/master` is fresh (avoids phantom diff entries)
37
+ - Default: commits on the current branch since divergence from `origin/master`
38
+ - Override: explicit range, SHA list, or branch from the user
39
+ - No commits ahead of master: tell the user, do not fabricate
40
+
41
+ 3. **Gather, in this order**
42
+ - **Git** (highest): `git log origin/master..HEAD` for messages; `git diff origin/master...HEAD --stat` and targeted reads of the diff to understand intent. Read for *why*, not line-by-line.
43
+ - **PR if it exists**: `mcp__plugin_planetexpress_jira-tools__get_bitbucket_pr` for title/description, `mcp__plugin_planetexpress_jira-tools__get_bitbucket_pr_changes` for the change overview. Treated as part of git evidence.
44
+ - **User input** (middle): anything the user said in the conversation
45
+ - **Ticket** (lowest): `mcp__plugin_planetexpress_jira-tools__get_jira_ticket` for the description and recent comments. Context only; never overrides git.
46
+
47
+ 4. **Conflict resolution**
48
+ - Git contradicts user input or ticket → trust git, surface the discrepancy in chat (not in the JIRA comment), let the user decide
49
+
50
+ 5. **Draft** in the default voice and format (see next section). Choose format C only with a one-sentence justification.
51
+
52
+ 6. **Present in chat** — show the draft verbatim, exactly as it would appear in JIRA, followed by:
53
+ > Reply 'post' to publish to <KEY>, or give edits.
54
+
55
+ 7. **Wait for explicit approval (strict gate + edits)**
56
+ - Affirmative-and-explicit ("post it", "yes, post", "approved", "ship it") → post
57
+ - Edits ("shorter", "drop the second bullet", "mention X", "use format C") → revise, re-present, wait again
58
+ - Anything else (silence, questions, mixed feedback) → do **not** post; treat as edits or a question
59
+
60
+ 8. **Post** via `mcp__plugin_planetexpress_jira-tools__add_jira_comment` with the approved text. Confirm in chat with the comment URL/ID returned.
61
+
62
+ **Pre-post safety:** if the resolved ticket key looks suspicious (parsed key not found, multiple keys in branch name, JIRA returned 404 on the get) — confirm with the user before posting.
63
+
64
+ ## Voice & format
65
+
66
+ **Default format (B):** 3–6 brief bullets, one line each. Optional one-line lead-in for framing.
67
+
68
+ **Escalation pressure scales with bullet count.** 3–4 bullets is comfortable B. 5–6 bullets is borderline — pause and check whether they form natural groups (they often do). 7+ bullets almost always means the work has multiple workstreams and belongs in format C with thematic headers; resist the urge to keep flattening.
69
+
70
+ **Hard escalation to format C** (structured headers — workstream-themed, or *What changed* / *Why* / *Notes*) when bullets cannot carry the message because there is genuine nuance, multiple workstreams, or important context that would be lost in a flat list.
71
+
72
+ ## Breaking changes must stand out
73
+
74
+ A change that requires action from users / operators / API consumers is a breaking change. It must be visually distinct in the summary, regardless of format.
75
+
76
+ - **Format B**: prefix the bullet with `**Breaking:**`, or hoist it into a dedicated lead bullet above the rest.
77
+ - **Format C**: give it a dedicated `## Breaking changes` section, separate from the workstream sections. Don't bury it inside *What changed*.
78
+
79
+ A breaking change in the middle of a flat list reads as routine; the operator decision *do I need to act?* must be answerable from a scan.
80
+
81
+ **Voice:** past tense, third-person, neutral and factual. Describes what *happened on the ticket*, not what *I* did.
82
+
83
+ **Strong defaults — exclude unless they are the actual point of the ticket:**
84
+
85
+ - Code blocks or inline code
86
+ - File paths
87
+ - Class / method / function names
88
+ - Commit hashes, PR numbers (the PR link is on the ticket already)
89
+ - Enumerations of identifier-level adaptations made during the work — annotation renames, method-signature changes, constant collapses, parameter additions — **even when framed as a category** ("Spring Framework 7 API rewrites: ~150 `APPLICATION_JSON_UTF8` collapses, `HttpMessageNotReadableException` constructor change, ..."). Name the category, never enumerate the contents. The PR diff has the contents.
90
+ - Pre-existing state of the codebase — longstanding flaky tests, pre-existing failures, environmental issues, anything true regardless of this ticket. The summary describes what *this ticket* changed, not what's true about the codebase.
91
+ - Bullets that describe routine plumbing the reader would infer from the ticket title alone — "deps realigned to the new baseline", "modularization absorbed", "starters added where the autoconfig moved", "tests updated for new APIs", "compile errors fixed". The title already implies this happened; bullets should describe specific consequences (breaking changes, non-obvious decisions, surprising scope) — never routine work.
92
+
93
+ **Exception clause:** include any of the above when the work *is* about that specific thing — a ticket whose whole point is "introduce `FooService`" can name it; a ticket about "extract the auth helper" can mention the extraction.
94
+
95
+ ## Headers must not soften impact
96
+
97
+ A header tells the reader the *kind* of thing they're about to read. A header that re-frames or softens its content is misleading and should be rejected.
98
+
99
+ | ❌ Wrong | ✅ Right |
100
+ |---|---|
101
+ | Breaking change filed under "Behaviour preserved but worth flagging" | "Breaking change" |
102
+ | Removed feature filed under "Minor cleanup" | "Removed: <feature>" |
103
+ | New required configuration filed under "Internal refactor" | "New required configuration" |
104
+
105
+ If a header does not fit its content, change the header — never re-cast the content to fit a softer header.
106
+
107
+ **Length:** scannable. If a bullet runs past one line, it is probably too detailed — collapse or split.
108
+
109
+ ### Example pair
110
+
111
+ Hypothetical ticket: *"Upgrade Spring Boot to 4.x"*.
112
+
113
+ **❌ Bad (code-heavy, low-level):**
114
+
115
+ > I bumped `spring.boot.version` in `gradle.properties` from `3.5.0` to `4.0.0`, then in `api-gateway/build.gradle.kts` I had to update `org.springframework.boot:spring-boot-starter-webflux` to align. The `ServerSecurityConfig.java` had to swap `ServerHttpSecurity#authorizeExchange` for the new `authorizeHttpExchange` API:
116
+ > ```java
117
+ > http.authorizeHttpExchange(spec -> spec.anyExchange().authenticated());
118
+ > ```
119
+ > Also updated `suppressedVulnerabilities.xml` for new Sonatype findings (CVE-2025-XXXX, CVE-2025-YYYY). All tests pass.
120
+
121
+ **✅ Good (high-level, format B):**
122
+
123
+ > Upgraded Spring Boot to 4.x across the build.
124
+ >
125
+ > - Reactive security configuration was migrated to the new exchange-authorisation API
126
+ > - Test fixtures in modules using the old security config were updated to match
127
+ > - Suppressions were extended to cover the new Sonatype findings introduced by the upgrade
128
+ > - All module test suites pass on the upgraded baseline
129
+
130
+ ## Edge cases
131
+
132
+ | Situation | Behaviour |
133
+ |---|---|
134
+ | No ticket key resolvable | Ask the user; do not guess |
135
+ | Multiple ticket keys in branch name | Ask which one; do not pick |
136
+ | No commits ahead of master | Say so; do not fabricate work |
137
+ | Branch is `master`/`main` | Refuse without explicit ticket + scope override |
138
+ | `get_jira_ticket` returns 404 | Confirm key with user before continuing |
139
+ | `add_jira_comment` fails | Surface the error verbatim; do not claim success |
140
+ | User input contradicts git | Trust git; flag the discrepancy in chat (not in the comment) |
141
+
142
+ ## Red flags — STOP and reconsider
143
+
144
+ These thoughts mean the draft is drifting from the rules. If you catch one, revise before presenting.
145
+
146
+ | Thought | Reality |
147
+ |---|---|
148
+ | "The reviewer needs the file path so they know where to look" | The PR diff has the path. The ticket comment is the *why*, not the *where*. |
149
+ | "Bullets are too vague — let me add a code block" | Vague bullets need better wording, not code. Code belongs in the PR. |
150
+ | "I should mention every commit so nothing is missed" | The summary is high-level. Commits the user cares about will be obvious from the result; the rest are noise. |
151
+ | "User said 'looks fine' — that's approval" | Strict gate: needs an explicit "post"/"yes, post"/"approved"/"ship it". Anything else means wait. |
152
+ | "The ticket description says X happened, so I'll mention X" | If git does not show X, do not mention X. Surface the discrepancy in chat instead. |
153
+ | "I'll auto-post since the user already said yes once on a previous summary" | Each draft needs its own approval. Edits invalidate the prior approval. |
154
+ | "Without details, the bullet looks empty" | An empty-looking bullet is the goal when the change is genuinely small. Padding with implementation detail violates the principle. |
155
+ | "The category is too abstract — let me list what's in it" | The category is the right level. The enumeration belongs in the PR. |
156
+ | "These aren't renames — they're API *adaptations* / *rewrites*" | Same shape, same exclusion. Both are mechanical adjustments to upstream API changes. Both belong in the PR, not the ticket. |
157
+ | "This bullet about test status sets useful context" | Pre-existing test state is true regardless of the ticket. Anything that was true on master is not what the ticket changed. |
158
+ | "It's a breaking change but I'll soften it under 'worth flagging'" | A breaking change is a breaking change. Headers must not soften impact. |
159
+ | "The breaking-change bullet sits fine in the middle of the list" | Buried = routine-looking. Prefix with `**Breaking:**` or hoist into its own lead bullet / dedicated section. |
160
+ | "I'm at 8 bullets but they all flow as one list" | 7+ bullets almost always means multiple workstreams. Group them with thematic headers (format C). |
161
+ | "Worth listing the deps / starters / packages we touched" | If a reader of the ticket title would assume this happened anyway, the bullet adds nothing. Concrete consequences only — breaking changes, non-obvious decisions, surprising scope. Routine upgrade plumbing belongs in the PR. |
162
+ | "The bullet is generic-sounding but it's still true" | True ≠ informative. Test: would the reader have inferred this from the ticket title alone? If yes, cut. |
@@ -0,0 +1,177 @@
1
+ ---
2
+ name: write-releasenotes
3
+ description: Use when the user asks to write, create, update, or generate release notes for the current ticket branch — phrases like "write the release notes", "update releasenotes for HP-1234", "generate release notes", "add a changelog entry for this ticket". Triggers on requests to produce AsciiDoc release-note entries for a FirstSpirit/Gradle project's releasenotes subproject.
4
+ ---
5
+
6
+ # Release Notes
7
+
8
+ ## Overview
9
+
10
+ Writes or updates concise AsciiDoc release-note entries for the current ticket, in the project's `releasenotes` subproject. Entries are per-ticket, per-language (`de` and `en`), named typically `<ticket>-<type>.adoc`, and live in the "next" (unreleased) folders. If the placeholder files don't exist, generate them with the project's Gradle task (`createChore` / `createBugfix` / `createFeature`), then fill them from the **committed** changes on the ticket branch, matching the style of existing `releasenote*.adoc` files.
11
+
12
+ **Core principle:** Release notes describe *what changed for the reader* — concise, user-facing, present-tense. Not a commit log, not a file list. Match the existing house style exactly; when in doubt, imitate a real example rather than invent format.
13
+
14
+ **Applicability principle:** This skill only applies to projects wired for this release-notes mechanism. If there are no release-note files **and** no `create*` Gradle tasks, the skill is **not applicable** — say so and exit. Not applicable is a notice, not an error.
15
+
16
+ ## When to use
17
+
18
+ - User asks to write / update / generate release notes for the current work
19
+ - User invokes the skill with an explicit ticket: "release notes for HP-1234"
20
+ - Finishing a ticket branch and the changelog entry is still missing
21
+
22
+ ## When NOT to use
23
+
24
+ - User wants a JIRA comment recap of the work — use `summarise-for-jira-comment`
25
+ - User wants a full commit message — that is not this skill
26
+ - Project has no releasenotes subproject and no `create*` Gradle tasks — this skill is **not applicable** (see Step 2)
27
+
28
+ ## Workflow
29
+
30
+ ### 1. Identify ticket key and type
31
+
32
+ - **Key** — default: parse `[A-Z]+-\d+` from the current branch name (e.g. `feature/HP-1615-spring-boot-4` → `HP-1615`). Override: explicit key in the user message. Unresolvable or ambiguous (multiple keys) → ask; do not guess.
33
+ - **Type** — one of `chore` / `bugfix` / `feature`. **`chore` is the default.** Only pick `bugfix` or `feature` when the branch's committed changes are *obviously* a product bug fix or a product feature. The type drives both the filename and which Gradle task generates the placeholder.
34
+ - **Chore is the default** — use `chore` (`createChore`) whenever the work is not obviously a product feature or a product bug fix. In particular, when the changes are **primarily dependency/CVE bumps or small version updates**, the type is `chore` regardless of the JIRA `issuetype`.
35
+ - **Feature / bugfix** — use `feature` / `bugfix` only when the committed changes clearly implement a product feature or fix a product bug. The JIRA `issuetype` (fetched via `mcp__plugin_planetexpress_jira-tools__get_jira_ticket`) is a hint, not the deciding factor:
36
+ - `Bug` → lean `bugfix` — but confirm the diff is an actual product fix, not a dependency bump filed as a Bug.
37
+ - `Story` / `Improvement` / `New Feature` / `Epic` → lean `feature` — but if the diff is just version/CVE bumps, it is still a `chore`.
38
+ - Let the **committed diff win over the issuetype** when they disagree. **Never ask the user which type** — deciding this from the diff is the skill's job. When genuinely on the fence, fall back to `chore` (the safe default). Only `bugfix`/`feature` require positive evidence in the diff.
39
+
40
+ ### 2. Locate the releasenotes mechanism (applicability gate)
41
+
42
+ Discover, do not assume paths:
43
+
44
+ - **Existing note files** — find the releasenotes subproject and its examples:
45
+ ```
46
+ find . -iname 'releasenote*.adoc' -not -path '*/build/*'
47
+ ```
48
+ Also look for a directory named `releasenotes` (the subproject) and, under it, "next"/"unreleased" folders holding per-language notes.
49
+ - **Gradle tasks** — check the create tasks exist:
50
+ ```
51
+ ./gradlew tasks --all -q 2>/dev/null | grep -iE 'create(Chore|Bugfix|Feature)'
52
+ ```
53
+ (Use `gradlew.bat` on Windows; use the wrapper if present, else `gradle`.)
54
+
55
+ **Decision:**
56
+
57
+ | Existing `.adoc` notes | `create*` tasks | Action |
58
+ |---|---|---|
59
+ | yes | — | Applicable — proceed (use tasks if present to scaffold, else write files directly matching examples) |
60
+ | no | yes | Applicable — proceed (scaffold with the task) |
61
+ | no | no | **Not applicable** — emit the notice below and stop |
62
+
63
+ Not-applicable notice (verbatim intent, one message, then stop):
64
+
65
+ > This project has no release-notes files and no `createChore`/`createBugfix`/`createFeature` Gradle tasks. The release-notes skill is not applicable here.
66
+
67
+ ### 3. Check whether this ticket's note files already exist
68
+
69
+ Look for the per-language files for this ticket in the "next" folders, typically:
70
+
71
+ - `<ticket>-<type>.adoc` for **de**
72
+ - `<ticket>-<type>.adoc` for **en**
73
+
74
+ (The exact folder split by language follows the project layout — infer it from where existing `releasenote*.adoc` examples live. Some projects use `next/de/` + `next/en/`, others a language suffix. Match what you observe.)
75
+
76
+ - **Both exist** → skip Step 4; go to Step 5 to update them.
77
+ - **Missing (either)** → Step 4 to generate placeholders.
78
+
79
+ ### 4. Generate placeholder files via Gradle
80
+
81
+ Run the task matching the type. Task naming convention:
82
+
83
+ | Type | Task |
84
+ |---|---|
85
+ | chore | `./gradlew createChore` |
86
+ | bugfix | `./gradlew createBugfix` |
87
+ | feature | `./gradlew createFeature` |
88
+
89
+ - These create the placeholder `.adoc` files in the next folders and **may bump the project version** — that side effect is the task's, not yours; report it if it happens.
90
+ - The task may prompt for a ticket/summary or take properties (e.g. `-Pticket=HP-1234`). Inspect existing filenames and, if the task fails on missing input, surface its output and ask the user for the exact invocation rather than guessing flags.
91
+ - If the task exits non-zero, surface stderr verbatim and stop. Do not hand-create files as a silent fallback unless the user asks.
92
+
93
+ Re-check that the expected `<ticket>-<type>.adoc` files now exist before continuing.
94
+
95
+ ### 5. Gather the committed changes (source of truth)
96
+
97
+ Only **committed** changes on the ticket branch are relevant — ignore the working tree and staged-but-uncommitted edits.
98
+
99
+ - Base = the main branch (usually `main`). Compute the range:
100
+ ```
101
+ git log --oneline $(git merge-base main HEAD)..HEAD
102
+ git diff $(git merge-base main HEAD)..HEAD --stat
103
+ ```
104
+ - Read commit messages and the diff to understand *what changed for the reader*. Pull the JIRA summary/description (Step 1 fetch) for the user-facing framing.
105
+ - If there are no commits on the branch beyond base, say so and ask whether to proceed (nothing to describe yet).
106
+
107
+ ### 6. Draft — concise, house-style, both languages
108
+
109
+ - **Study first.** Open 1–3 existing `releasenote*.adoc` examples and match their AsciiDoc structure, heading level, bullet vs prose, tense, and length exactly. Imitate; don't invent format.
110
+ - **Concise.** One entry per ticket. Typically 1–3 lines / a short bullet. Describe the change and its user impact, not the mechanics. No file paths, class names, or commit hashes unless the change *is* about that.
111
+ - **Both languages.** Write `de` and `en` entries with equivalent meaning — the `de` version in German, the `en` in English. Keep them in sync; don't leave one as a placeholder.
112
+ - Preserve any template tokens/attributes the placeholder came with (ticket reference, version attribute) — fill them, don't delete them.
113
+
114
+ **Security / dependency content policy (mandatory):**
115
+
116
+ Release notes describe *product* changes for the reader. They are not a security bulletin.
117
+
118
+ - **Never name CVEs.** No `CVE-YYYY-NNNNN` identifiers in the notes. If a dependency was bumped, just state that it was updated — keep it short. Prefer the *what*, not the *why-security*.
119
+ - **Never mention CVE suppressions**, `dependency-check` suppressions, `suppressedVulnerabilities.xml`, or any suppression bookkeeping. That is internal maintenance, never reader-facing. Omit it entirely.
120
+ - **Dependency updates are fine** to mention — but framed as a product-relevant update, concise, and without the security rationale. New capability or behaviour from the bump is worth a line; a routine version bump for hygiene is a one-liner or folded into a general "dependencies updated" note.
121
+ - If the *only* substance of the ticket is CVE/suppression handling with no reader-facing effect, the entry is a short chore note that dependencies were updated — not a list of vulnerabilities addressed.
122
+
123
+ Rewrite, don't transcribe. Bad → good:
124
+
125
+ - Bad: `Logback wurde auf Version 1.5.38 aktualisiert, um CVE-2026-13006 zu beheben. Die Dependency-Check-Unterdrückungen für die ausstehenden Micrometer-CVEs wurden aktualisiert.`
126
+ Good: `Logback wurde auf Version 1.5.38 aktualisiert.`
127
+ - Bad: `Das AWS SDK wurde aktualisiert, um die transitiven Denial-of-Service-Schwachstellen CVE-2026-54399 und CVE-2026-54428 in Apache HttpComponents Core (httpcore5) zu beheben.`
128
+ Good: `Das AWS SDK wurde aktualisiert.`
129
+
130
+ ### 7. Present for approval, then write
131
+
132
+ **Pre-approval at invocation:** if the user pre-authorized writing when invoking the skill — e.g. "write the release notes and apply them", "no need to confirm", "just do it", "and commit" — skip the gate below and write directly. Still show the final content in chat after writing. Pre-approval covers only writing the files; it never extends to committing unless the user said so explicitly.
133
+
134
+ Otherwise, show the exact content for both files verbatim (path + body), then:
135
+
136
+ > Reply 'write' / 'apply' to write these files, or give edits.
137
+
138
+ - Affirmative-and-explicit → write both files with `Edit`/`Write`.
139
+ - Edits → revise and re-present; wait again.
140
+ - Anything else (silence, "looks good", a question) → treat as edits/question; do **not** write.
141
+
142
+ Do not commit. Report the written file paths. If Step 4 bumped the version, mention it.
143
+
144
+ ## Edge cases
145
+
146
+ | Situation | Behaviour |
147
+ |---|---|
148
+ | No ticket key resolvable from branch or message | Ask; do not guess |
149
+ | Multiple ticket keys in branch name | Ask which one |
150
+ | No `.adoc` notes and no `create*` tasks | Not applicable — emit the notice, stop (not an error) |
151
+ | `get_jira_ticket` fails / type unclear | Decide from the committed diff; fall back to `chore`. Never ask the user for the type |
152
+ | Gradle task not found though examples exist | Write the files directly, matching an existing example's layout |
153
+ | Gradle task fails or needs unknown input | Surface output verbatim; ask for the exact invocation; don't guess flags |
154
+ | Gradle task bumps the version | Report the version change; it is the task's side effect, not yours |
155
+ | Note files already exist for this ticket | Skip generation; update them in place |
156
+ | No commits on branch beyond base | Say so; ask whether to proceed |
157
+ | Only uncommitted/working-tree changes | Ignore them — committed changes only; tell the user to commit first if the branch is empty |
158
+ | Language layout unclear | Infer from where existing examples live; if genuinely ambiguous, ask |
159
+ | User approves for one language only | Write only what was approved; re-present the other |
160
+ | User pre-approved at invocation ("write and apply", "just do it") | Skip the approval gate; write directly, then show the content. Commit only if the user also said so explicitly |
161
+
162
+ ## Red flags — STOP and reconsider
163
+
164
+ | Thought | Reality |
165
+ |---|---|
166
+ | "I'll invent a clean AsciiDoc format" | Match the existing `releasenote*.adoc` house style. Imitate a real example. |
167
+ | "I'll list the changed files / classes" | Release notes are user-facing. Describe the change's impact, not the mechanics. |
168
+ | "I'll describe my uncommitted work too" | Only committed changes on the branch count. |
169
+ | "English is enough" | Both `de` and `en` must be written and in sync. |
170
+ | "No release-notes setup — I'll create the whole mechanism" | If there are no notes and no `create*` tasks, the skill is not applicable. Say so and stop. |
171
+ | "I'll hand-create placeholders instead of running Gradle" | Use the `create*` task when it exists — it also handles version/layout. Hand-create only when tasks are absent or the user asks. |
172
+ | "Longer notes look more complete" | Concise wins. One short entry per ticket. |
173
+ | "I'll name the CVE so the reader knows what was fixed" | Never name CVEs in release notes. A bumped dependency is just "updated to X" — keep it short. |
174
+ | "I'll note that the suppressions were updated" | CVE/dependency-check suppressions are internal bookkeeping — never reader-facing. Omit entirely. |
175
+ | "The JIRA type is Story, so it's a feature" | Type follows the committed diff, not the issuetype. CVE/version-bump work is a `chore` even when filed as a Story/Bug. Default to `chore` unless it's obviously a product feature or product bug fix. |
176
+ | "I'll just write the files, they're only release notes" | Present both files for approval first — unless the user pre-approved at invocation. Otherwise write only on explicit go. |
177
+ | "User said 'write and apply' but I'll confirm anyway to be safe" | Pre-approval means skip the gate. Write directly, then show what you wrote. |