Draft release notes for the Jira ticket: the argument (text following the release-notes: trigger)
release-notes: produces a customer-facing release-notes draft for a Jira
Value Increment (or any ticket) from pre-exported markdown in the user's Obsidian vault.
It optionally grounds the prose in merged PR diffs, renders the dynatrace-docs authored
release-notes body — a {{#context}} label + ### title + prose for the feature-updates /
breaking-changes destinations, or one bare past-tense sentence for fixes — with no
{{#internal-note}}, no Jira IDs, no PR links (the docs automation adds the metadata
wrapper), runs a light style gate, and writes the draft to a persistent destination for the
user to paste into Jira's release-notes field.
For full feature documentation use document:; for Epic drafting use epics:.
This command makes zero external API calls and never writes into the docs repo (release-notes pages there are generated by Jira-driven automation).
Phase 0 — Load
Resolve the Jira input via the shared front-end. Execute
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/jira-input-resolution.mdagainst the argument (text following therelease-notes:trigger).release-notes:is jira-driven only: expectmode: jira-drivenwithjira_key,jira_export_root(the ticket export dir —$VAULT_PATH/jira-products/<KEY>for a JiraID, or the passed directory), andsource. The front-end owns the$VAULT_PATH/jira-productsvalidation and Fallbacks A/B. Carryjira_key,jira_export_root, andfocus_keyforward.If the front-end returns
mode: direct(no Jira input), stop withRELEASE_NOTES_NEEDS_JIRA: release-notes: needs a Jira key or an imported-Jira directory.— this command has no direct-prompt behavior.
Specs-repo preflight. Cite
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md
and execute its specs-preflight entry point (§3) inline: flush any leftover
session artifacts from an earlier run, retry an artifact commit that failed to
push, and settle the branch. This runs against $SPECS_PATH only —
git -C "$SPECS_PATH", never a cd, so the code/docs repo this run is working
in is untouched (§1 rule 1). Prompt-free and silent when the specs repo is clean
and on its default branch. If a guard fires, emit its §5 notice; if it returns
specs_git: blocked (§3.3 G0), carry that flag for the whole run — the terminal
commit-artifacts step skips on it.
Phase 1 — Clarification
Rule: Ask, don't guess. Group questions; use choices arrays; the last choice MUST be "Other… (describe)".
Diff grounding (default OFF — Jira content is usually enough for release notes):
choices: ["Jira content only (Recommended)", "Also ground in merged PR diffs (you'll pick repos)", "Cancel", "Other… (describe)"]If "ground in PR diffs", additionally ask the two sub-questions below.
Repos search base (
$REPOS_PATH) (only if diff grounding is ON). Read${REPOS_PATH:-/workspace}; may be a colon-separated list. Ask:choices: ["Use $REPOS_PATH (default /workspace) (Recommended)", "Use a different path (you'll be prompted)", "Cancel", "Other… (describe)"]Clones are located in Phase 4 by matching
git remoteagainst each PR's repo slug — not by assuming a<base>/<slug>directory name.PR status filter (only if diff grounding is ON):
choices: ["MERGED only (Recommended)", "All PRs (MERGED + OPEN + DECLINED)", "Specific list (you'll be prompted)", "Other… (describe)"]Output destination. Always write to a file (console-pasted markdown loses formatting in Jira). Resolve the default by
$VAULT_PATH:$VAULT_PATHset → resolve the ticket's persistent Obsidian project folder (the durable home — NOTjira-products/, regenerated on every import):
Default =find "$VAULT_PATH/Projects" -maxdepth 5 -type d -name "<jira_key>*" 2>/dev/null | head -1<project-dir>/<jira_key>-release-notes.md. If no project folder is found (e.g. a non-PRODUCT-ticket), use the derived default below.$VAULT_PATHunset (directory input) → default<parent-of-jira_export_root>/<jira_key>-release-notes.md. Then ask (the Recommended choice is always the resolved file):
choices: ["Write to <default file> (Recommended)", "Write to a different absolute path (you'll be prompted)", "Print to screen only", "Skip writing", "Other… (describe)"]Print-to-screen and Skip remain available but are never the default. The default is persistent (host-mounted; survives container restart, unlike
/tmp). NEVER offer or accept a path inside a docs repo or underjira-products/.Style check (default ON when the
dt-style-guideplugin is installed):choices: ["Run dt-style-checker then apply safe fixes (Recommended)", "Run dt-style-checker, report only (no auto-fix)", "Skip style check", "Other… (describe)"]
Also display: resolved jira_export_root, jira_key (plus $VAULT_PATH when set), $REPOS_PATH (or "N/A — Jira-only"), and the resolved destination.
Phase 1.5 — Classify
Load and follow the model-routing policy at ~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/model-routing.md, then classify the task. Release-notes drafting is MODERATE (bounded prose synthesis from a single ticket; no Opus planning or review gate). State the classification and a one-sentence reason.
Phase 2 — Worthiness check + plan/approval
Worthiness gate. Read
relevant_for_release_notesdirectly from the imported VI frontmatter underjira_export_root(this phase runs before Phase 3, so there is nojira-readerhandoff yet, andjira-readerdoes not surface this field in any case). NEVER read it from the authored specs draft.false/no→ stop:RELEASE_NOTES_NOT_RELEVANT: <jira_key> is flagged not relevant for release notes; Jira's status rule does not require one.Offer an override for drafting ahead of the flag:choices: ["Cancel — nothing to draft (Recommended)", "Draft anyway — I'll set the flag later", "Other… (describe)"]true/yes→ proceed.- absent → proceed silently. The field defaults to true; absent is not false.
release_versionsplays no part in this gate.Plan. Before presenting the plan, run
resolve-docs-grounding release-notesper~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/docs-grounding.md— this is the run's only consent-bearing step (an index build or a capped refresh), so it must resolve here, before Phase 3'sjira-readerand Phase 4/5's diff resolution do any of the run's real work. Present: resolvedjira_key, destination, diff-grounding on/off (+$REPOS_PATHand repos to scan when on), style-check choice, and thedocs grounding:line thatresolve-docs-groundingreturned, verbatim — including itsretrieval:value and any index-build, staleness, or shadowing clause (off switch: --no-docs). Ask:choices: ["Approve & continue (Recommended)", "Revise plan", "Cancel"]
Phase 3 — Read Jira
Invoke jira-reader. Use depth: vi-only when diff grounding is OFF; depth: full when ON (to collect PR URLs from the hierarchy's ## Pull Requests sections).
→ task(agent_type: "dev-workflows:jira-reader"):
"Return the structured handoff for this brief:
jira_export_root: [resolved jira_export_root] jira_key: [resolved jira_key] depth: [vi-only | full]"
When focus_key is set (explicit <VI> <Epic>), scope the Phase 6 render input
to the focus Epic's subtree — the focus Epic plus its linked descendants — so the
release note covers that Epic's user-facing changes rather than the whole VI. This
scopes only what Phase 6 renders; it does not mutate the stored handoff that other
phases read. When focus_key is null, the draft covers the whole ticket/VI exactly as
today.
If status: NOT_FOUND / EMPTY, surface ["Re-enter key", "Cancel"].
On OK, capture imported_change_type and imported_release_notes_category from the jira-reader
handoff's value_increment block (null when absent). Do NOT parse release_versions — the draft
carries one Summary and never names a version. Do NOT read the authored specs-draft VI for these
fields: they are Jira-mirror fields (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/vi-format.md), so an authored
VI never carries them.
Phase 4 — Resolve repos (only if diff grounding is ON)
Build a slug→clone map: for each top-level directory under each entry of $REPOS_PATH, run timeout 5 git -C <dir> remote get-url origin 2>/dev/null, strip a trailing .git, and take the URL's last path segment as the clone's slug. Resolve each in-scope PR repo slug against the map: one match → use it; multiple → auto-prefer basename ending -repo, then _repo/_fast, then alphabetically last; zero matches → escalate:
choices: ["Skip and continue without its PRs", "I'll clone it — wait", "Cancel", "Specify a different absolute path for this repo", "Other… (describe)"]
Phase 5 — Diff summarisation (only if diff grounding is ON)
Spawn diff-summarizer in batches of up to 4 concurrent agents per task message, passing each resolved absolute repo_path plus repo_url_slug and the PRs filtered to that repo. Collect the outputs into a diff_summaries array.
Per-repo summarizer status. Handle each returned status before continuing:
OK/PARTIAL/NO_PRS_RESOLVED— use the result; record unresolved PRs in the run report.REPO_MISSING— escalate per theRepo missing (after resolution)rule in~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/escalation-rules.md.DIRTY_TREE— escalate per theDirty working treerule in the same file.REFRESH_BLOCKED— escalate per theRefresh blockedrule in the same file.prep.read_only: true— not a failure. Resolution ran atprep.scanned_ref. Escalate per theRead-only mount — ref stale or divergedrule only whenprep.ref_committed_atis more than 14 days old orprep.head_divergence.ahead > 0; otherwise proceed silently.
Diff grounding is opt-in and advisory here: a repo the user skips degrades the grounding, never the run.
Phase 5.5 — Documentation grounding dispatch (optional)
docs_grounding was already resolved in Phase 2 — consume that cached result here; never re-run resolve-docs-grounding. When docs_grounding: ON, dispatch-docs-grounder with feature_summary = the ticket goal + release themes, jira_key = jira_key. Carry the digest into Phase 6 with writer-attach consumption. When OFF, skip silently. (Independent of diff grounding.)
Phase 6 — Render the draft
Resolve run_phase. release-notes: runs at two points in a VI's life, and the
release-note-types.md §4 documentation-link rule depends on which. Glob the VI's specs dir
($SPECS_PATH/specifications/<jira_key>-*/) for specification.md and design.md:
- neither present →
run_phase: pm. The feature is not built and its documentation does not exist yet, so the note carries no documentation link and the skill never asks for one. - either present →
run_phase: dev. The author may supply a redirect short link that will later point at the pagedocument:publishes. $SPECS_PATHunset or the dir missing →run_phase: pm(the safe default — it only suppresses a link, never fabricates one).
Do not add a question for it.
→ task(agent_type: "dev-workflows:release-notes-writer"):
"Render the release-notes draft for this brief:
jira_reader_handoff: [the Phase 3 handoff — scoped to the focus Epic's subtree when focus_key is set] diff_summaries: [the Phase 5 array, or omit when diff grounding was off] docs_grounding: [the Phase 5.5 digest, or omit when OFF/EMPTY] imported_change_type: [from Phase 3, else null] imported_release_notes_category: [from Phase 3, else null] run_phase: [pm | dev — resolved immediately above, in this phase] model_routing: [the block from Phase 1.5] code_repos: [the Phase-4 resolved {slug, path} map when diff grounding is on; omit otherwise]"
If status: PARTIAL, surface each gaps entry with recommended_action: "ask user" and let the user supply the label/prose or accept a <!-- TODO --> marker.
For a field: change_type gap, the destination was inferred with low confidence — and the
destination decides the draft's whole shape. Confirm it by consequence, never by enum label.
This fires ONLY when imported_change_type was null; when the Jira dropdown is already set, no
prompt appears.
State the inference, then ask:
This note reads like a
<proposed type>, so the draft is shaped as<shape>and lands in<destination>.
choices: ["<proposed type> — <its shape>, in <its destination> (Recommended)", "Feature update — titled section with a docs link, in feature-updates.md", "Breaking change — titled section with remediation steps, in breaking-changes.md", "Fix — one self-contained sentence, in fixes.md", "Other… (describe)"]
Drop the option that duplicates the recommended one. Apply the choice to
release_notes_block.change_type (Feature update → New technology support, Breaking change →
Breaking change, Fix → Bug fix) + destination and re-render the draft in the chosen shape —
switching between fixes and a titled destination changes the body structure, not just a label. The
chosen value never becomes text in the draft; the PM still sets the Jira dropdown.
For a field: deprecation_eol gap (a deprecation was detected but the required
end-of-life date is unclear), ask the user:
choices: ["Enter the end-of-life date (you'll be prompted; end-of-support optional)", "Leave the <!-- TODO: end-of-life date --> marker in the draft", "This isn't a deprecation — drop the note", "Other… (describe)"]
On a supplied date, replace the <!-- TODO: end-of-life date --> placeholder with the
end-of-life date (and end-of-support date when given), formatted per the dt-style-guide
(e.g. November 30, 2026).
When release-notes-writer returns gaps[] entries that have jira_phrasing and source_phrasing (source-truth discrepancies), present the discrepancy table and per-claim prompt as in document: (Jira mode) Phase 5.8:
- Show the analysis table (claim, Jira phrasing, source phrasing, location).
- Ask:
choices: ["Decide per discrepancy (Recommended)", "Document ALL as actual (code)", "Document ALL as intended (Jira)", "Skip ALL and report (drafts a bug report)", "Cancel", "Other… (describe)"] - Apply the decision to the draft prose:
document-as-code→ use source phrasing;document-as-spec→ use Jira phrasing (no marker in release notes prose — the gap is recorded only in the gaps file);skip-and-report→ omit the claim. - For
document-as-specorskip-and-report: resolvebug_report_destinationthe same way as the release-notes destination —$VAULT_PATHset → thefind "$VAULT_PATH/Projects" -maxdepth 5 -type d -name "<jira_key>*"project folder;$VAULT_PATHunset →<parent-of-jira_export_root>/. Write/append<bug_report_destination>/<jira_key>-implementation-gaps.mdusing the §7.5 format from~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/source-truth.md, settingSpec phrasing:to(no spec)(this flow has no spec).
Pass code_repos (the Phase-4 resolved map) to the writer when diff-grounding is on.
Phase 7 — Style gate (optional)
If the user chose a style check AND the dt-style-guide plugin is installed:
→ task(agent_type: "dt-style-guide:dt-style-checker") on the combined_rendered draft (write it to the destination first when the destination is a file, or pass it inline). If violations are returned and the user chose auto-fix:
→ task(agent_type: "dt-style-guide:dt-doc-fixer") to apply safe fixes.
If dt-style-guide is not installed, skip this phase and note "style check skipped — dt-style-guide not installed" in the report.
Phase 8 — Write + report
Write the
combined_rendereddraft to the resolved destination:file:<path>→ write it. If the file exists, ask:["Overwrite", "Write to <path>.new", "Print to screen instead", "Skip"].stdout→ include the full draft in the report under### Release-notes draft.skip→ do not write. NEVER write into a docs repo.
Report:
## Release-notes draft — <jira_key> - Destination: <path | stdout | skipped> - Shaped as: <Feature update | Breaking change | Fix> → <destination file> (source: <imported | inferred>) - Context label: <the {{#context}} value | none — omitted from the draft> - Deprecation: <EOL <date> (end-of-support <date | —>) | none> - Diff grounding: <on (repos: …) | off> - Style check: <applied N safe fixes | report only (M findings) | skipped (dt-style-guide absent)> - Reminder: paste this into the ticket's Jira release-notes field — the docs automation adds the {{#internal-note}} metadata and emits it into dynatrace-docs. ### Next step [leaf/closure per `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/next-phase-offer.md` — guidance only, never auto-invoked: the release note is drafted. If earlier pipeline phases remain, continue — hand to PA → `create-ard: <VI>` or PE → `epics: <VI>`; if the change is already built and documented, the VI is fully processed.] ### Context hygiene The resume pointer is written in the terminal maintenance phase (Phase 10), per `session-hygiene.md` §1. Then: - **Release note drafted and the VI fully processed?** → nothing to suggest — you're done. - **A PA/PE phase still pending for this VI (e.g. `create-ard:`, `epics:`), even yourself?** → run **`/clear`** before switching roles. - Consider **`/rename <VI-ID>-<slug>-pm`** to relocate this session later. Guidance only — see `~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md`.
Phase 9 — Session maintenance & feedback
Terminal phase — runs AFTER the Phase 8 report is composed; NEVER interrupts
an earlier phase. release-notes: has no built-in maintenance agent, so this
phase invokes impl-maintenance on the Sonnet detection chain and then
persists the plugin-facing slice of its report as session feedback.
- Invoke
impl-maintenance(task(agent_type: "dev-workflows:impl-maintenance", model:<detection chain — claude-sonnet-4.6, fallback claude-sonnet-4.5/gpt-5.4>)):"Analyse this session and return a Lessons Learned report.
Session handoff:
- Command run: release-notes:
- What was done: [one-paragraph summary of the release-notes draft produced]
- Key events: [source-truth discrepancies, PARTIAL renders, style-check failures, ambiguous destinations — or 'none']
- Workarounds used: [manual steps not automated by the workflow — or 'none']
- Review verdict: N/A (light gate only, no Opus review)
- Test result: N/A (no tests in release-notes:)
- Project root: [the resolved jira_export_root or the destination directory]"
- Persist plugin feedback (automatic). Project the report's plugin-facing
slice into the specs repo by citing
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.mdand calling itsemit-autoentry point (§6). Pass the Lessons Learned report,command: release-notes:, the run'sjira_keyandsource, andplugin_version(read from~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/.plugin/plugin.json).emit-autorenders only the report's Command workflow improvements, New agents / skills, and plugin Reference docs sections plus the Key observations that triggered them (§4) — never target-projectcopilot-instructions.md/hook advice — asorigin: autoentries, dedupes by stableid(§3), resolves the target via the §2 specs-first ladder, and writes silently. - Surface the persisted path (or "no plugin-facing signal — nothing persisted") as this phase's only output.
Phase 10 — Emit follow-up tasks
Terminal phase — runs AFTER the Phase 8 report and the Phase 9 feedback phase;
NEVER interrupts an earlier phase. Persist the run's manual-step follow-ups by
citing
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/followup-emission.md and executing its steps
inline.
- Collect the qualifying follow-ups: the mandatory manual publish step ("paste this release-notes draft into the ticket's Jira release-notes field") and any implementation-gap signals surfaced during the run.
- Filter them with the reference's §6 qualifying predicate.
- Resolve the write target via the §4 ladder using
jira_keyandsource; render + place tasks and verbose notes per §1–§3; dedupe per §5. The task references the draft file written in Phase 8 rather than duplicating it. - Preview + confirm per §7 (
approve-all | select | cancel), then write.
ADDITIVE — the follow-ups also remain in the Phase 8 report. This phase NEVER
fails the run, NEVER commits (still true — this phase only writes follow-up
files; those writes are committed by the terminal commit-artifacts step
below, in this same phase, per
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md
§4), NEVER makes an external API call, and NEVER writes into a docs repo or the
current working directory.
Then write the resume pointer. Cite
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md
§1 and write/overwrite <VI-dir>/dev-workflows/resume.md now — after the
feedback and follow-up entries above, so the pointer reflects the completed run,
and before the commit step below, so it is included in it. Redact per §1.
Silent; the printed ### Context hygiene guidance already appeared in the Phase
8 report.
Then commit session artifacts (terminal). Cite
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md
and execute its commit-artifacts entry point (§4) inline — the LAST action of
the run. It stages ONLY the §2.1 bounded artifact paths inside $SPECS_PATH,
commits <KEY> Add dev-workflows session artifacts (release-notes:), and pushes
per §4 step 5. It NEVER writes into a docs repo — the release-note draft is
untouched — NEVER touches a code repo, the vault, or the
current working directory; NEVER force-pushes; NEVER fails the run; and skips
entirely when the run carries specs_git: blocked (§3.3 G0), re-emitting that
notice. Because the Phase 8 report was composed before this phase, print its
§6 outcome line here, as the run's last output — prefixed Specs repo:, with
any guard notice repeated in full.
ADDITIVE — this phase NEVER fails the run, NEVER commits the deliverable (the
release-notes draft is a plain file for manual paste into Jira; the terminal
step above commits only the bounded session-artifact paths in $SPECS_PATH),
NEVER makes an external API call, and NEVER writes into a docs repo or the
current working directory.
Invariants (always enforced)
- ALWAYS
emit-block(per~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/feedback-emission.md) before escalating a halt caused by a plugin / skill / command / reference gap (a capability the run needed but the plugin lacked) — so a run abandoned at the block still records it. NEVER for a work-quality review BLOCK or an environment / user halt (repo-missing, dirty-tree, jira-not-found, cancellation). - ZERO external API calls — PR URLs are identifiers only; all resolution is local
git. jira-readeris read-only.- The draft contains NO Jira IDs/keys, NO PR links, and NO
{{#internal-note}}block. - The draft is EXACTLY one Summary, shaped by its destination per
~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/release-note-types.md§1/§3 — a{{#context}}label +### title+ prose forbreaking-changes/feature-updates, or ONE bare past-tense sentence forfixes. It carries NOChange type:line, NORelease-notes category:line, and no title or prose that names the release version. When the change deprecates something the Summary carries a deprecation note (end-of-life date required, end-of-support optional). - The
{{#context}}label IS the importedrelease_notes_category, used verbatim; when the import carries none the line is OMITTED. Change Type is sourcedimported_change_type→ infer, and is confirmed with the user ONLY when it was inferred with low confidence — by shape and destination, never by enum label. Neither field is ever asked for as a Jira dropdown value. - The run is GATED on the imported
relevant_for_release_notes: an explicitfalsestops withRELEASE_NOTES_NOT_RELEVANT(overridable); absent proceeds silently. - NEVER write into a docs repo; the default destination is persistent (never
/tmp). - ALWAYS use
choicesarrays; the last choice is always"Other… (describe)". - Light gate only — no Opus review, no tests, no branch (still true —
specs-preflightswitches$SPECS_PATHonly between branches that already exist, and only plugin-created ones (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md§2.2); it creates none), and no commit of the draft or of anything in a docs/code repo, the vault, or the current working directory. The terminalcommit-artifactsstep commits ONLY$SPECS_PATH's bounded artifact paths (~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md§2.1). - ALWAYS run
specs-preflightat Phase 0 andcommit-artifactsas the run's last action (per~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/specs-repo-git.md) — bounded to$SPECS_PATH's artifact paths (§2.1) and to plugin-created branches (§2.2), alwaysgit -C "$SPECS_PATH"and never acd(§1 rule 1), never force-pushing, and never failing the run - ALWAYS end the Phase 8 report with a
### Next steprecommendation (per~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/next-phase-offer.md) — guidance only, never auto-invoked; the pipeline leaf (adaptive: continue any pending PA/PE phase, else the VI is fully processed). - ALWAYS end the Phase 8 report with a
### Context hygieneblock per~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md— prepare-first (theresume.mdwrite runs later, in the terminal maintenance phase, per~/.copilot/installed-plugins/ihudak-copilot-plugins/dev-workflows/skills/_shared/session-hygiene.md§1 — this block prints the guidance only), then a leaf-aware suggestion (done → nothing; pending role →/clear) +/rename <VI-ID>-<slug>-pm; guidance only, never auto-run.