Draft a customer-facing release note for a Jira ticket from its context and linked merge requests. Read-only unless the user opts in to publish. Use when the user says "draft release notes", "write a release note", "release note for [TICKET-KEY]", or invokes /issue-draft-release-notes.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add risadams/ink-and-agency --skill issue-draft-release-notes --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Issue Draft Release Notes?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/risadams-issue-draft-release-notes)More formats (shields.io, HTML) on the badges page.
---
name: issue-draft-release-notes
category: business-product
codex-short-description: "Draft a customer-facing release note for a Jira ticket from ticket + MR context"
description: >
Draft a customer-facing release note for a Jira ticket from its context and linked merge
requests. Read-only unless the user opts in to publish. Use when the user says "draft
release notes", "write a release note", "release note for [TICKET-KEY]", or invokes
/issue-draft-release-notes.
allowed-tools:
- Read
- Bash
- AskUserQuestion
- Agent
- Skill
- mcp__atlassian__jira_get_issue
- mcp__atlassian__jira_get_comments
- mcp__atlassian__jira_get_remote_links
- mcp__atlassian__jira_get_changelog
- mcp__atlassian__jira_search
- mcp__atlassian__jira_add_comment
- mcp__atlassian__jira_update_issue
- mcp__gitlab-mcp__list_merge_requests
- mcp__gitlab-mcp__get_merge_request
- mcp__gitlab-mcp__get_merge_request_diffs
- mcp__gitlab-mcp__list_merge_request_changed_files
related-skills:
- clarity-council
- writing-humanize
- technical-writer
loop-eligible: false
compatibility: claude-code codex opencode
---
# Issue — Draft Release Notes
Read-only drafting of a customer-facing release note for a Jira ticket. Gathers ticket context and related MR code changes, synthesizes a release note matched to the audience, runs a quality pass, and (only on opt-in) posts it back to the ticket.
**Read-only by default.** The skill never modifies code, MRs, Confluence, or Jira fields. The single permitted write is in Phase 6 — and only after explicit user opt-in: posting the note as a Jira comment, or setting a Release Notes field.
## Input
A Jira ticket key — pattern `[A-Z][A-Z0-9]+-\d+` (e.g. `PRJ-1234`). Extract from the user's message. If no key is present, ask for one. Default project key (if the user gives only a number) is read from memory (`reference_jira_default_project.md`).
## Workflow
```text
Release-Notes Progress:
- [ ] Phase 1: Gather ticket context
- [ ] Phase 2: Find & analyze related MRs / code changes
- [ ] Phase 3: Determine audience & note type
- [ ] Phase 4: Draft the release note
- [ ] Phase 5: Quality pass (clarity-council + writing-humanize)
- [ ] Phase 6: Optionally publish back to the ticket (user opt-in)
```
### Phase 1 — Gather ticket context
- `jira_get_issue` — summary, description, issue type, status, priority, components, labels, **fix version(s)**, affected version, resolution.
- `jira_get_comments` — capture what was actually implemented vs. originally scoped; watch for "done / shipped in" notes.
- `jira_get_remote_links` — capture linked GitLab MR URLs and Confluence pages.
The **issue type** and **fix version** strongly shape the note: a `Bug` reads as a fix, a `Story`/`Feature` as a capability, a `Task` may be internal-only (flag it). Compile a short **Context Summary** and present it.
### Phase 2 — Find & analyze related MRs / code changes
Locate merge requests tied to this ticket:
1. **From remote links** — any GitLab MR URLs captured in Phase 1; fetch each via `get_merge_request`.
2. **By search** — `list_merge_requests` filtered on the ticket key (MR titles and branch names usually embed it, e.g. `feature/PRJ-1234-...`). Limit to the most relevant 5.
3. For each relevant MR: read the **title, description, and changed-files list** (`list_merge_request_changed_files`). Pull diffs (`get_merge_request_diffs`) **only** when the description is thin and you need to infer user-visible behavior — release notes describe *what changed for the user*, not line-level detail. If a diff exceeds ~2000 lines, rely on the file list + MR description.
Resolve the GitLab project path from memory (`reference_gitlab_config.md`) — do not hardcode URLs. If no MRs are found, note that and draft from the ticket context alone.
Produce a one-line **"what actually changed"** takeaway per MR.
### Phase 3 — Determine audience & note type
Pick the note's framing from the ticket type and content. If genuinely ambiguous, ask the user once via `AskUserQuestion`:
- **Audience** — *Customer/end-user* (default), *Operator/admin*, or *Internal/developer*.
- **Type** — `New feature` · `Enhancement` · `Bug fix` · `Security fix` · `Deprecation` · `Breaking change` · `Internal (no customer-facing note)`.
If the change is purely internal (refactor, test, CI), recommend **Internal — no customer note** and confirm before drafting anyway.
### Phase 4 — Draft the release note
Write the note in the [RELEASE-NOTE-FORMAT.md](RELEASE-NOTE-FORMAT.md) structure. Core rules:
- **No icons or emoji.** Plain-text headline and body only.
- **Lead with user value**, not implementation. "You can now…" / "Fixed an issue where…" — not "Refactored the X handler."
- **Plain language.** No ticket jargon, no internal class/module names unless the audience is developers.
- **One note per ticket**, tight: a headline + 1–3 sentences. Add a "Details / Impact" line only when it changes user behavior (action required, defaults changed, migration needed).
- **State the fix version** if known.
- For **bug fixes**, describe the symptom the user saw, not the root cause.
- For **breaking changes / deprecations**, always include an **Action required** line.
### Phase 5 — Quality pass
1. Invoke `/clarity-council` (multi mode) with personas **Technical Writer**, **Product Owner**, and **Customer Advocate**:
- **user_problem:** "Is this release note accurate, clear, and appropriately scoped for its audience?"
- **context:** the draft note + Context Summary + per-MR "what changed" takeaways + chosen audience/type.
- **desired_outcome:** "A release note that a {audience} reads in 10 seconds and understands what changed and whether they must act. Flag any claim not supported by the ticket/MR evidence, and any leaked internal jargon."
- **depth:** standard.
- **Technical Writer** owns clarity and scannability; **Product Owner** owns value framing and scope accuracy; **Customer Advocate** owns "does this answer the user's 'what's in it for me / do I need to do anything?'".
2. Incorporate the findings. Then run the note prose through the `/writing-humanize` skill to strip AI-tells (em-dash overuse, rule-of-three, inflated phrasing) so it reads naturally.
3. Present the final note in a fenced ```markdown block, plus a one-line note of the audience/type chosen and any claims that could **not** be evidenced (so the user can verify).
### Phase 6 — Optionally publish back to the ticket
Ask the user via `AskUserQuestion`:
> **Publish this release note to `{TICKET-KEY}`?**
> - **No** *(recommended default)* — end the skill, nothing posted.
> - **Post as a comment** — add it as a Jira comment.
> - **Set Release Notes field** — write it into a Release Notes field (only offer this if such a field exists on the ticket).
**If "No":** end with one sentence — *"Release note kept local. Nothing posted."*
**If "Post as a comment":**
1. Read [jira-comment-template.md](jira-comment-template.md) (sibling file).
2. Render the note in **Jira wiki markup** (headings `h2.`, bold `*text*`, code `{code}`, panels `{panel}`) per the template's mapping — not GitHub markdown.
3. Append the AI disclaimer panel from the template **verbatim**.
4. Post via `jira_add_comment` (`page_id` = ticket key, `body` = rendered note).
5. Confirm with the ticket key.
**If "Set Release Notes field":** only if Phase 1's `jira_get_issue` revealed a Release Notes custom field. Confirm the exact field name with the user, then `jira_update_issue` with that field set to the plain-text note (no disclaimer panel — fields are not comments). If no such field exists, fall back to the comment option.
If a write fails (permissions, network), surface the error and offer to retry or keep the note local — never swallow the failure.
## Constraints
- **Read-only across all systems, with one explicit exception.** The only permitted writes are `jira_add_comment` or `jira_update_issue` (Release Notes field), in Phase 6, after explicit opt-in. Never modify code, MRs, or Confluence.
- Never auto-publish. Phase 6 always goes through the explicit prompt, even if the user opted in during a prior session.
- The disclaimer panel is mandatory whenever a **comment** is posted. Do not edit, soften, or omit it.
- **Do not invent changes.** Every claim in the note must trace to the ticket or an MR. If evidence is thin, say so and draft conservatively rather than embellish.
- No internal jargon, ticket numbers, or class names in customer/operator notes (developer-audience notes may include them).
- **No icons or emoji** in the release note body or headline.
- Do not write files to disk unless the user explicitly asks to save the note.
- If no MRs are found and the ticket context is too thin to describe a user-visible change, stop and tell the user — a release note needs something concrete to describe.
## Quality Loop
Before returning the artifact, evaluate it and refine if it falls short.
1. **Generate** the artifact via the workflow above.
2. **Self-evaluate** against these criteria:
- Note is written for the target audience (customer-facing, not internal jargon)
- Content is grounded in the ticket + linked MR changes, not invented
- Fix version and issue type are reflected correctly
- Read-only respected — nothing posted unless the user opts in
3. **Loop** — if two or more criteria fail, revise and re-check.
4. **Exit** when all criteria pass, or after two refinement passes (then note which criteria still fall short).
> **Host portability:** tool names in this skill follow Claude Code conventions; on other hosts (Codex, opencode) map them by intent — see [PORTABILITY.md](../PORTABILITY.md).
<!-- self-evolve:start -->
## Self-Evolve Loop
Journal: `~/.ink-and-agency/learnings/issue-draft-release-notes.md` (workspace-local
`.ink-and-agency/learnings/issue-draft-release-notes.md` where the sandbox confines writes). Read it
first, append what the run taught last — [SELF-EVOLVE.md](../SELF-EVOLVE.md).
<!-- self-evolve:end -->
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!