skill-author
Write a new portable Agent Skill (a SKILL.md folder) from a described task, for Claude Code, Codex, Copilot, Cursor, Kiro or Antigravity in any repo — a description that leads with the artifact and ends with trigger phrases, decisive steps, a quality bar, when and when-not sections naming near-miss siblings, anti-patterns, a non-interactive rule, reference files and scripts that work in every tool, acceptance evals and trigger queries, and the install path for each tool. Use when the user says "turn this into a skill", "write a SKILL.md for…", "make an agent skill that…", or wants a repeatable task packaged so their coding agent does it the same way every time.
Other ways to install
With the sibling skills it hands off to:
The whole pack it belongs to:
By hand, from a clone of the repo:
In Claude Code, with the skill-engineering plugin installed, invoke it as:
Try it
A realistic prompt from the skill's acceptance evals:
Make me an agent skill for Northwind's support team: every Monday someone pastes last week's Zendesk ticket export (CSV with id, subject, tags, created_at, status) and wants a one-page digest with the top five themes, counts per theme, and three example ticket ids each. We use Codex and Cursor. We already have a skill called incident-summary for single outages and one called csat-report for survey scores. It should never make up ticket counts.
What a good result looks like
Example output
Example: from a described task to a finished skill · the skill's own worked example, source
Every release I paste our merged PRs into the chat and ask for customer-facing notes, and every time I have to explain the format again. Can you make this a skill? We use Claude Code and Copilot at Acme. We already have
sprint-statusandlaunch-postskills in the repo.
The interview (one message)
The user had already given the tools, the repo and two siblings, so the interview asked only for the gaps:
Before I write it, three things. Reply "go" to take the defaults.
- What makes the notes good? Default: grouped New / Improved / Fixed, breaking changes first, one line per PR in user terms with the PR number, internal changes dropped.
- What would you type to ask for it? Default: "write the release notes", "draft the changelog for v2.4", "what shipped this sprint, for customers".
- Anything it must never make up? Default: changes or benefits that no PR states.
The user replied: "go, and breaking changes need a 'what to do' line."
Decisions made without asking
- It is a skill: a repeatable task with one artifact. Not an AGENTS.md rule.
- Name:
release-notes-from-prs. The input is in the name because "release notes" alone would also claim roadmap-driven announcements, which belong tolaunch-post. - No script. Sorting and rewriting PR titles is judgment, not arithmetic.
- Boundaries: the sprint report goes to
sprint-status, the announcement tolaunch-post. Each appears in When NOT to use and as a should-not-trigger query. - Install:
.claude/skills/for Claude Code, which Copilot CLI also reads. Add.github/skills/for Copilot in the editor.
.claude/skills/release-notes-from-prs/
├── SKILL.md
├── templates/release-notes.md
└── evals/
├── evals.json
└── eval_queries.json
SKILL.md
---
name: release-notes-from-prs
description: Write customer-facing release notes from a list of merged pull requests — grouped into New, Improved and Fixed, each line in user terms with the PR number, internal-only changes dropped, and breaking changes called out first. Use when the user pastes merged PRs or a git log and says "write the release notes", "draft the changelog for v2.4", or "what shipped this sprint, for customers".
---
# release-notes-from-prs
You turn a list of merged pull requests into release notes a customer can read in a minute.
The input is engineering language; the output says what changed for the person using the
product. Internal changes (refactors, CI, dependency bumps with no user effect) are dropped,
and the user sees the list of what was dropped.
## How to respond
1. **Ask once for what's missing.** You need the merged PRs (titles, numbers, and bodies or
labels if available), the version and release date, and the audience (end users or
developers using an API). Ask in one message; default the audience to end users.
2. **Sort every PR into one bucket:** Breaking, New, Improved, Fixed, or Internal. A PR with
a `breaking` label or a removed option goes to Breaking even if it also adds something.
3. **Rewrite each kept PR as one line in user terms.** ✅ *"Exports now include the time zone
(#412)"* ❌ *"Refactor ExportSerializer to pass tz (#412)"*. Keep the PR number.
4. **Put Breaking first**, each with what the user must do. A breaking change with no action
line is not finished.
5. **Fill [`templates/release-notes.md`](templates/release-notes.md)** and list the dropped
Internal PRs under the notes, so the user can overrule you.
**Non-interactive runs** (subagent, CI, headless): with no PR list, emit
`BLOCKED: need the merged PRs (titles and numbers)` and write nothing. A missing version or
date becomes `[assumption] version: unreleased`.
## Useful references in this skill
- [`templates/release-notes.md`](templates/release-notes.md) — the release-notes skeleton
## Quality bar
- **Every line traces to a PR number** from the input. Nothing is added that no PR supports.
- **Lines are in user terms**: what changed for the user, not which class changed.
- **Breaking changes come first** and each carries the action the user must take.
- **Dropped PRs are listed**, so nothing disappears silently.
## When to use this skill
- ✅ Release notes or a changelog entry from merged PRs or a git log
- ✅ A "what shipped" summary for customers at the end of a sprint
## When NOT to use this skill
- ❌ An internal sprint report for the team: use `sprint-status`
- ❌ A launch announcement or blog post, which needs positioning, not a list: use `launch-post`
## Anti-patterns to avoid
- ❌ **Copying PR titles verbatim.** "Bump lodash to 4.17.21" means nothing to a customer.
- ❌ **Hiding a breaking change under Improved** because it also adds a feature.
- ❌ **Inventing a benefit** ("faster exports") that no PR measured.
templates/release-notes.md
# {Product} {version} — {YYYY-MM-DD}
## Breaking changes
- {what changed} — **what to do:** {action} (#{n})
## New
- {line in user terms} (#{n})
## Improved
- {line} (#{n})
## Fixed
- {line} (#{n})
---
Dropped as internal: #{n} {title}, …
evals/evals.json
{
"skill_name": "release-notes-from-prs",
"evals": [
{
"id": 1,
"prompt": "Write the release notes for Acme Tasks v2.4 (shipping 2026-10-15) from these merged PRs: #401 Add CSV export for boards; #405 Remove legacy v1 API tokens (breaking); #407 Refactor board serializer; #409 Fix due dates shifting a day for users in UTC-8; #410 Bump eslint to 9.1.",
"assertions": [
"The removal of v1 API tokens (#405) appears first, under Breaking, with an action the user must take",
"Every line carries a PR number from the prompt, and no line describes a change that no PR supports",
"#407 and #410 are dropped as internal and listed under the notes",
"The due-date fix is written in user terms, not as the code change",
"No performance or benefit claim appears that the PR titles do not state"
]
}
]
}
evals/eval_queries.json
[
{"query": "Write the release notes for v2.4 from these merged PRs", "should_trigger": true},
{"query": "Draft the changelog entry from this git log", "should_trigger": true},
{"query": "What shipped this sprint? Make it readable for customers", "should_trigger": true},
{"query": "Turn these PR titles into customer-facing notes for the release", "should_trigger": true},
{"query": "Write the launch blog post for our new export feature", "should_trigger": false},
{"query": "Give me a status update on the sprint for the engineering manager", "should_trigger": false},
{"query": "Review this pull request for bugs before I merge it", "should_trigger": false}
]
Install
mkdir -p .claude/skills .github/skills
cp -R release-notes-from-prs .claude/skills/ # Claude Code, and Copilot CLI
cp -R release-notes-from-prs .github/skills/ # Copilot in the editor
Check
The folder was linted with skill-review's script, against the two sibling skills in the same repo. This is the real output:
$ python3 lint_skill.py release-notes-from-prs --siblings .
lint_skill: release-notes-from-prs (release-notes-from-prs)
skill_md_lines=57 description_chars=388 evals=1 assertions=5 trigger_queries=4 near_miss_queries=3 siblings_compared=2
closest: sprint-status 0.07, launch-post 0.05
no findings
result: 0 error(s), 0 warning(s), 0 info -> mechanical checks pass
The lint passing covers only the mechanical checks. Next: run the eval prompt in a fresh session and mark each assertion.
How it's checked
Measured against plain Claude Code (2026-10-23): it met 72% of its checks, against 52% without it, and a blind judge preferred the agent without it. How skills are checked
21 assertions across 3 acceptance evals, and 8 trigger queries. Every skill's checks
What the output must do
When it should and shouldn't activate
Should activate:
- Turn this prompt I keep pasting into a reusable skill for Claude Code
- Write a SKILL.md that makes our agent draft API changelogs the same way every time
- Make an agent skill that converts our Jira export into a sprint summary, it has to work in Copilot and Cursor
- Help me package our code-review checklist as a skill for Codex
Should leave to another skill:
- Add a new skill to the skilldrop catalogue with its manifest and catalogue row
- Review my existing skill folder and tell me if it's ready to publish
- Generate eval cases for the SKILL.md I already have
- Write an AGENTS.md for this repo so agents stop running npm when we use pnpm
Hands off to
- skill-review — when the skill folder is written. Audit routing, portability, safety, structure and evals before the skill is shared.
Related skills
agents-md-generator, eval-harness-generator
Source
SKILL.md · the whole folder on GitHub.