Skip to content
Back to skills

Writing Changelogs

ASecurity

Writes human-friendly changelog entries and release notes. Use when populating changelog, preparing releases, or reviewing release notes quality.

  • 10 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 1, 2026
ai-agentsgoreactrefactoringgitapisecurityperformancedocumentation

Works with

  • api
  • mcp

Security analysis

A100/100

Scanned October 7, 2026

npx -y skills add dork-labs/dorkos --skill writing-changelogs --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Writing Changelogs?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Writing Changelogs
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dork-labs-writing-changelogs/badge)](https://www.skillsdirectory.com/skills/dork-labs-writing-changelogs)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: writing-changelogs
description: Writes human-friendly changelog entries and release notes. Use when populating changelog, preparing releases, or reviewing release notes quality.
---

# Writing Changelogs

Write changelog entries and release notes that humans actually want to read. This skill activates when writing changelog entries, preparing GitHub releases, or reviewing release notes quality.

**Sources**: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), [Common Changelog](https://github.com/vweevers/common-changelog)

## When to Use

- Writing a changelog fragment for a change
- Preparing GitHub release notes via `/system:release`
- Reviewing changelog entries before release
- Transforming commit messages into user-friendly descriptions

## Where entries live: fragments

Unreleased entries do **not** go in `CHANGELOG.md`. Each change adds one **fragment** file
under `changelog/unreleased/` — a coordination-free scheme that keeps parallel worktrees from
colliding on a shared `[Unreleased]` block (ADR `260707-231641`; full guide in
`changelog/README.md`). The workflow:

- **Filename** — `<YYMMDD-HHMMSS>-<kebab-slug>.md`: a timestamp id from `.claude/scripts/id.ts`
  followed by a short slug. The post-commit hook names it from your commit subject.
- **Body** — optional `covers:` frontmatter (which commits this fragment covers; the
  post-commit hook fills it in, and the PR check reads it so your prose stays free to be
  rewritten for a human), then one or more `### Category` headings (Added, Changed, Deprecated,
  Removed, Fixed, Security) with bullets written per the principles below. One fragment may
  carry multiple categories.
- **Creation** — the `post-commit` hook writes a fragment from each conventional commit; curate
  it (or hand-author one) before opening a PR. **Never edit `CHANGELOG.md`'s `[Unreleased]`
  section** — it no longer holds entries.
- **Release** — `/system:release` compiles all fragments into the new `## [X.Y.Z]` section and
  deletes them. Only the release process writes `CHANGELOG.md`.

The entry-quality guidance below applies identically to fragment bullets.

## Core Principles

Changelog entries are user-facing prose, so the **`writing-for-humans`** skill sets the readability bar: 9th-grade level, one idea per sentence, benefit before mechanism, every acronym glossed. Read it first. The rules specific to changelogs:

1. **Communicate impact, not implementation** - Focus on what users can DO, not what files changed
2. **Use imperative verbs** - "Add", "Fix", "Remove" not "Added", "Fixed", "Removed"
3. **Include references, but never let them carry the meaning** - Link to commits, PRs, or issues where they exist; the sentence must stand alone without the `(DOR-123)` or `(#42)`
4. **Internal notes never ship** - batch, task, and tracking entries ("Batch 9 — acceptance PASS") get cut at curation, not published
5. **Only what ships** - an entry describes what works in the release, never a roadmap item; the demo-claim gate in `meta/positioning-202610/00-overview.md` decides. The story words come from that file and `writing-for-humans` ("Telling the DorkOS story"): agents are co-workers doing a job, not assistants, and the reader is usually the founder running a business with them

## Entry Format

### Basic Template

```markdown
- [Imperative verb] [user benefit/what changed] ([reference])
```

### With Sub-details (for significant changes)

```markdown
- **[Feature Name]** - [User benefit explanation]
  - [Technical detail 1]
  - [Technical detail 2]
```

## Good vs Bad Examples

| Bad (Developer-focused)                           | Good (User-focused)                                            |
| ------------------------------------------------- | -------------------------------------------------------------- |
| Add workspace_manager.py for auto workspace setup | Open project folders without manual setup                      |
| fix: Use relative paths in theme commands         | Fix theme commands failing when run from different directories |
| Accept 'default' as theme alias                   | Use 'default' to quickly apply the standard theme              |
| Add changelog-populator.py hook                   | Changelog entries are now auto-generated from commits          |
| Update AGENTS.md with new patterns                | (Skip - internal documentation, not user-facing)               |
| refactor: Extract helper function                 | (Skip - internal refactoring, no user impact)                  |

## Imperative Verbs Reference

| Verb          | Use For                            | Example                                 |
| ------------- | ---------------------------------- | --------------------------------------- |
| **Add**       | New features, capabilities         | Add dark mode support                   |
| **Fix**       | Bug corrections                    | Fix login failing on Safari             |
| **Change**    | Modifications to existing behavior | Change default timeout to 30 seconds    |
| **Remove**    | Deleted features                   | Remove deprecated v1 API                |
| **Improve**   | Performance, UX enhancements       | Improve search speed by 50%             |
| **Update**    | Dependencies, configurations       | Update to React 18                      |
| **Deprecate** | Scheduled for removal              | Deprecate XML export (use JSON instead) |

## What to Skip

Not everything belongs in the changelog, and the test is **audience, not commit type**: the changelog's reader _operates_ DorkOS. A change only someone _building_ DorkOS notices ships no fragment, even when it lands as `feat:` or `fix:`. Skip:

- Internal refactoring with no user impact
- Documentation typo fixes
- Development-only changes (CI, tests, linting)
- Harness, ADR, and contributor-documentation changes — the builders' record lives in git history, `decisions/`, and `contributing/`, not here
- Dependency updates (unless security-related)
- Code style changes
- Fixes to changes that haven't been released yet (see below)

**Exception**: Include if it affects how users interact with the system.

### The audience test

The "You can now" test has a companion: **if the "you" is a DorkOS contributor rather than someone running DorkOS, the entry doesn't ship.** Watch for builder-facing work dressed in user language — test coverage, build tooling, code moves between packages — rewritten so smoothly it reads like a feature. The tell: nothing an operator sees or does changed.

How to satisfy the PR gate for builder-only work: the `fragment-present` check requires coverage for every `feat:`/`fix:`/`refactor:`/`perf:` commit, and `no-fragment-under-skip-label` makes fragment and label mutually exclusive — so a builder-only PR takes the **`skip-changelog` label**, never a fragment. In a **mixed PR** (user-facing and builder-only commits together), write the fragment for the user-facing part and add the builder-only commit subjects to its `covers:` list: coverage is independent of prose, so the gate stays green without shipping builder bullets.

### Fixes to unreleased changes

If a bug was introduced after the last release, no user ever saw it — from the reader's side the feature simply ships working. A separate "Fix …" bullet only tells them about a bug they could never have hit ([Common Changelog](https://github.com/vweevers/common-changelog) makes this an explicit rule).

- **Writing the fragment**: write it as usual. At commit time you rarely know whether the feature will release before the fix, and the PR check wants the commit covered. If the fix lands on the same branch as the feature it fixes, fold it into the feature's fragment instead (move the `covers:` items across).
- **At release**: `/system:release` classifies every Fixed bullet (Phase 4 curation) and drops the ones that fix behavior introduced since the last tag. If the fix changed what a user should _know_ about the feature — a limitation lifted, behavior that settled differently from the feature's entry — that substance folds into the feature's Added/Changed entry rather than surviving as a Fixed line.
- **When unsure** whether the buggy behavior existed at the last tag: keep the fix. Over-including is harmless; wrongly dropping a real fix is not.

## Theme Blockquote (Optional)

Add a single-line blockquote below version headings to provide a theme/summary for the release:

```markdown
## [0.3.0] - 2026-02-20

> DorkOS 0.3.0 adds a scheduler and dynamic MCP tools.

### Added

- ...
```

This theme line feeds:

- Blog post descriptions
- GitHub Release "What's New" opening paragraph
- Quick reference for users scanning the changelog

The blockquote is optional and backward-compatible. Older versions without it work fine.

## Changelog Categories

Use these standard categories in order:

1. **Added** - New features
2. **Changed** - Modifications to existing features
3. **Deprecated** - Soon-to-be removed features
4. **Removed** - Removed features
5. **Fixed** - Bug fixes
6. **Security** - Vulnerability fixes

## GitHub Release Notes Template

When creating GitHub releases, use this narrative format (different from the changelog):

```markdown
## What's New in vX.Y.Z

[1-2 sentence theme describing the focus of this release]

![Shot alt text](https://dorkos.ai/product/archive/vX.Y.Z/<shot-id>-dark.png)
_[One line caption. See it move → [docs page or /features section]]_

### Highlights

🎨 **[Feature Name]** - [One sentence explaining the benefit and how to use it]

📂 **[Feature Name]** - [One sentence explaining the benefit and how to use it]

🔧 **[Fix/Improvement]** - [One sentence explaining what's better now]

### All Changes

- [Bullet list of all changes - can be slightly more technical]
- [Include references: (#123) or (abc1234)]

**Full Changelog**: https://github.com/[owner]/[repo]/compare/v[prev]...v[new]
```

**Rule: every release with user-visible UI changes includes at least one visual.** Embed the shot's poster PNG from the version's frozen archive (`archive/vX.Y.Z/<shot-id>-<theme>.png` — never the live `/product/<file>` path, which repoints on the next capture and would change what an old release shows). GitHub renders PNG/GIF inline but does not play `.webm`, so link the caption to a docs page or `/features` section for the motion version instead of linking the webm directly. The `/system:release` media phase (Phase 6.6) selects and archives these shots before this step runs.

### Emoji Reference for Highlights

| Emoji | Use For                     |
| ----- | --------------------------- |
| ✨    | Major new feature           |
| 🎨    | UI/UX improvements, themes  |
| 📂    | File handling, organization |
| 🔧    | Fixes, improvements         |
| ⚡    | Performance                 |
| 🔒    | Security                    |
| 📝    | Documentation               |
| 🗑️    | Removals, deprecations      |

## Pre-Release Checklist

Before publishing release notes, verify each entry:

- [ ] Starts with imperative verb (Add, Fix, Change, Remove, Improve)
- [ ] Describes user benefit, not just implementation detail
- [ ] Reads at a ~9th-grade level (no unexplained jargon; every acronym glossed or cut)
- [ ] No ticket ID carries the meaning: the sentence stands alone without `(DOR-123)` or `(#42)`
- [ ] No internal batch/task/tracking entries: those are cut at curation, never shipped
- [ ] The reader is someone operating DorkOS, not someone building it (see "The audience test")
- [ ] Appropriate for someone who doesn't know the codebase
- [ ] Passes the demo-claim gate: nothing unbuilt or unverified reads as working

For the overall release:

- [ ] Has a theme sentence summarizing the release focus
- [ ] 2-3 highlights with context for significant changes
- [ ] Link to full changelog for details

## Transforming Commit Messages

When converting conventional commits to changelog entries:

| Commit Message                   | Changelog Entry                                                 |
| -------------------------------- | --------------------------------------------------------------- |
| `feat: Add workspace_manager.py` | Add automatic project workspace setup                           |
| `fix(theme): Use relative paths` | Fix theme commands failing outside project root                 |
| `feat!: Change config format`    | **BREAKING**: Change configuration format (see migration guide) |
| `chore: Update deps`             | (skip)                                                          |
| `docs: Fix typo`                 | (skip)                                                          |

### Breaking Changes

Always make breaking changes prominent:

```markdown
### Changed

- **BREAKING**: [Description of breaking change]
  - Migration: [How to update]
```

## Integration with /system:release

During release preparation:

1. **Analysis phase**: Transform raw changelog entries to user-friendly language
2. **Preview phase**: Show transformed entries for approval
3. **GitHub release**: Generate narrative release notes using the template
4. **Quality check**: Apply the pre-release checklist

## Writing Tips

### The "You Can Now" Test

For each entry, mentally prepend "You can now..." - if it doesn't make sense, rewrite it.

- ❌ "Add workspace_manager.py" → "You can now add workspace_manager.py" (nonsense)
- ✅ "Open project folders automatically" → "You can now open project folders automatically" (makes sense)

### The "So What?" Test

If someone asks "so what?" after reading your entry, you need more context.

- ❌ "Fix path handling" → So what?
- ✅ "Fix theme commands failing when run from different directories" → Clear impact

### Avoid These Patterns

- Starting with "This release..." (the heading already says the version)
- Using passive voice ("was added" vs "Add")
- Listing file names without explaining benefit
- Technical jargon without explanation
- Commit hash references without descriptions

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.