From 3commas
Generate business-level release note digests for a domain by gathering Jira tickets and GitHub PRs, correlating them, and producing a categorized summary. Use when the user asks to generate release notes, create a domain digest or changelog, see what shipped or changed, produce a weekly digest, or summarize what was released for a date range.
npx claudepluginhub 3commas-io/commas-claude --plugin 3commasThis skill uses the workspace's default tool permissions.
Generate a categorized, business-level digest of what shipped in a domain over a given date range. Pulls from Jira (done tickets) and GitHub (merged PRs), correlates them, and synthesizes a summary suitable for engineering leads and product managers.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Automates semantic versioning and release workflow for Claude Code plugins: bumps versions in package.json, marketplace.json, plugin.json; verifies builds; creates git tags, GitHub releases, changelogs.
Generate a categorized, business-level digest of what shipped in a domain over a given date range. Pulls from Jira (done tickets) and GitHub (merged PRs), correlates them, and synthesizes a summary suitable for engineering leads and product managers.
User says something like:
Before gathering any data, verify both integrations are working. Run these checks in parallel:
getAccessibleAtlassianResources tool. If it fails, STOP and tell the user: "Atlassian MCP is not connected. Set up the Atlassian MCP integration before running release notes."gh auth status via Bash. If it fails, STOP and tell the user: "GitHub CLI is not authenticated. Run gh auth login first."Both must succeed. No fallbacks. No partial results.
Extract two pieces of information from the user's request:
YYYY-MM-DD format using today's date as reference:
{today - 3} to {today}2026-03-24 to {today}{today}If the user doesn't specify a date range, ask them for one.
Read skills/release-notes/domains.yaml. Use the Glob tool to find the file: search for **/skills/release-notes/domains.yaml. This works regardless of where the plugin is installed.
If the file is not found, check for domains.yaml.example and tell the user: "Copy domains.yaml.example to domains.yaml and fill in your domain configuration."
Look up the requested domain name under the domains key. Extract:
jira.base_url — the Jira instance URL (e.g., https://your-instance.atlassian.net)jira.project — the Jira project key (e.g., PROJ)jira.done_statuses — list of statuses that mean "done" (e.g., ["Done", "Resolved", "Closed"])slack.channel — the Slack channel to post to (e.g., #platform-release-notes)github.org — the GitHub organization (e.g., your-org)github.repos — list of repository namesIf the domain is not found, list all available domains from the YAML and ask the user to pick one.
Fetch Jira tickets and GitHub PRs in parallel — issue all tool calls in a single message.
Use the Atlassian MCP searchJiraIssuesUsingJql tool with this JQL:
project = {jira.project} AND status changed to ("{status1}", "{status2}", ...) DURING ("{start_date}", "{end_date}")
Replace {jira.project} with the project key and {status1}, etc. with each entry from jira.done_statuses. Replace dates with the parsed absolute dates.
From the results, extract for each ticket:
PROJ-1234)For each repo in github.repos, run via Bash:
gh pr list --repo {github.org}/{repo} --state merged --search "merged:{start_date}..{end_date}" --json number,title,body,mergedAt,headRefName --limit 100 --jq '[.[] | .body = (.body[:500])]'
This truncates PR bodies to 500 characters to avoid wasting context on verbose descriptions.
Issue all repo queries as separate Bash tool invocations alongside the Jira MCP call — all in a single response message for parallel execution.
If any repo returns exactly 100 PRs, warn the user that results may be truncated and suggest narrowing the date range.
From each PR result, extract:
If any Jira query or any single gh call fails: STOP immediately. Show the user the exact error and which tool/repo failed. Do not continue with partial data.
For each merged PR, scan its title and headRefName (branch name) for Jira key patterns matching the domain's project. The pattern is: {jira.project}-\d+ (e.g., PROJ-123, PROJ-4567).
Produce three buckets:
All three buckets feed into the synthesis step. Uncorrelated PRs and uncorrelated tickets are classified into the same four categories using whatever information is available (PR title/body or ticket summary/type).
Using all three buckets from Step 4, produce a categorized release notes digest.
Classify each change into one of these categories (skip empty categories in the output):
Use the Jira issue type as a hint (Bug → Bug Fixes, Story → likely New Features), but override based on the actual content when the type is misleading.
Omit these from the digest entirely:
(PROJ-123). Do NOT include PR links, multiple Jira links, or full URLs inline. If a change spans multiple tickets, mention the primary one and note "and related tickets."If there are 30+ items after correlation, group related changes more aggressively. Combine PRs that address the same feature area into a single entry. The digest should be scannable in under 2 minutes.
## {Domain} Domain — Changes {start_date} to {end_date}
### New Features
- **{Title}** — 2-3 sentence description of what's new and why it matters. (PROJ-123)
### Bug Fixes
- **{Title}** — 2-3 sentence description of what was broken and how it's fixed. (PROJ-456)
### Improvements
- **{Title}** — 2-3 sentence description of what got better. (PROJ-789)
### Infrastructure / DevOps
- **{Title}** — 2-3 sentence description of what changed operationally.
If no merged PRs and no done tickets exist in the date range, output:
No notable changes in {domain} for {start_date} to {end_date}.
After generating the digest, format it for Slack and post it to the domain's configured channel using the Slack MCP slack_send_message tool.
Slack uses mrkdwn, not Markdown. Convert the digest as follows:
Headers: Use bold text with emoji on its own line.
## Platform Domain — Changes ... → *📋 Platform Domain — Changes Mar 13 to Mar 27, 2026*Item titles are clickable links. The title should link to the primary source:
*<{jira.base_url}/browse/{KEY}|{Title}>* — e.g., *<https://your-instance.atlassian.net/browse/PROJ-100|New Feature Name>**<https://github.com/{org}/{repo}/pull/{number}|{Title}>*Item body: Plain text, 2-3 sentences. The only exception for links in the body: if the change includes relevant documentation (API docs, strategy language guides, etc.), include a clickable link using Slack format <url|link text> — e.g., "See <https://docs.example.com/api|updated API docs>."
No parenthetical ticket references. In Slack format the title IS already the clickable link to the primary ticket. Do NOT add "(PROJ-123)" or "(PROJ-123, PROJ-456, ...)" at the end of the body text — that's redundant and clutters the message. If multiple tickets contributed to one item, that's fine — just link the primary one in the title and don't list the rest.
No service or repo names. Don't mention internal service names or repo names. Describe what the service does in plain terms instead — e.g., "the execution engine" not the repo name, "the data service" not its internal codename.
Spacing:
——— between category sections*📋 {Domain} Domain — Changes {start_date} to {end_date}*
🚀 *New Features*
• *<jira_url|Title>* — 2-3 sentence description.
• *<jira_url|Title>* — 2-3 sentence description.
———
🐛 *Bug Fixes*
• *<jira_url|Title>* — 2-3 sentence description.
• *<pr_url|Title>* — 2-3 sentence description.
———
✨ *Improvements*
• *<jira_url|Title>* — 2-3 sentence description.
———
⚙️ *Infrastructure / DevOps*
• *<jira_url|Title>* — 2-3 sentence description.
Post as a single message. The entire digest must be sent in one slack_send_message call — do NOT split it into multiple messages. Slack supports messages up to 40,000 characters; the digest will fit.
Use the Slack MCP slack_send_message tool to post the formatted message to the channel from slack.channel in the domain config.
If the user didn't ask to post to Slack, show the formatted digest and ask: "Want me to post this to {slack.channel}?"
If Slack MCP is not available, show the formatted Slack message to the user and tell them to copy-paste it manually.