| name | updating-changelogs |
| description | Updates changelogs and bumps versions across multiple packages in a monorepo branch. Use when releasing features, preparing PRs, resolving changelog/version merge conflicts, or when user says "update changelog", "bump version", "prepare release", "version bump", or "resolve conflicts". |
Updating Changelogs
Update changelogs and versions across multiple packages after implementing a feature branch.
Quick Start
date +"%Y.%-m.%-d"
grep -m1 '^## ' <package>/ChangeLog.md
git diff origin/master...HEAD --name-only | cut -d/ -f1-2 | sort | uniq
find . -maxdepth 4 -iname '*changelog*' -type f 2>/dev/null | grep -v node_modules
🚨 Critical Rules
Date Format — NEVER Leading Zeros
date +"%Y.%-m.%-d"
- ✅
2026.1.17.0 ✅ 2026.1.5.0
- ❌
2026.01.17.0 ❌ 2026.1.07.0
Version Collision — ALWAYS Check Before Bumping
grep -m1 '^## ' <package>/ChangeLog.md
- If latest is
2026.1.17.0 and today is 2026.1.17 → use 2026.1.17.1
- If latest is
2026.1.17.1 and today is 2026.1.17 → use 2026.1.17.2
- Never blindly append
.0 — always check for collisions first
Content Quality — Feature-First, Not Commit-First
BEFORE writing, read the specs/proposal (openspec, PRD, issue) to understand what the PR delivers as a whole. Individual commits are implementation details — the changelog captures the feature.
Two-layer structure:
- Feature headline — What capability does the user/developer gain? Write this FIRST.
- Supporting details — Only list specifics that help someone decide if this version matters to them.
## 2026.2.18.0 -- 13.7.0
### Added
- API Refresh Token management page: list, create, reveal, copy, delete tokens
with inline panels and search. ADT state machine architecture.
### Infrastructure
- `UseStateEffect` module: reusable hook for state-driven async effects with
automatic cancellation and optional key-identity tracking.
Anti-pattern — commit-log regurgitation:
## 2026.2.18.0 -- 13.7.0
- Extract useStateEffect into standalone module
- Add optional ~toDepKey parameter
- Move Generate New button to left side
- Disable delete buttons during Revealing state
This tells you what changed in code but not what the PR delivers. A reader can't tell this is a brand new feature page.
Rule of thumb: If your entry reads like git log --oneline, you're writing at the wrong level. Read the specs, then write what matters to someone upgrading.
Omit: test additions, pure refactors, minor fixes (unless user-facing).
🚨 Special Cases (Memorize These)
| Package | Changelog Path | Casing | Format |
|---|
onping2.0/ | onping2.0/ChangeLog.md (ROOT, not nested) | ChangeLog.md | ## YYYY.M.D.patch |
re-react-onping-frontend/ | re-react-onping-frontend/Changelog.md | Changelog.md (lowercase L) | ## YYYY.M.D -- semver |
Wrong casing = file IGNORED by CI checks.
Workflow
1. Understand the Feature (DO THIS FIRST)
ls openspec/changes/*/proposal.md openspec/changes/*/design.md 2>/dev/null
git diff origin/master...HEAD --name-only | cut -d/ -f1-2 | sort | uniq
git log --oneline origin/master..HEAD -- <package>/
Write the feature headline from the specs, not from the commit log.
2. Match Existing Format
head -20 <package>/ChangeLog.md
3. Determine Version
ALWAYS check the latest version first:
grep -m1 '^## ' <package>/ChangeLog.md
| Type | Format | Bump Rule | Example |
|---|
| Date-versioned | YYYY.M.D.patch | Today's date, increment patch if date taken | 2026.1.17.0 → 2026.1.17.1 |
| Haskell 4-part semver | A.B.C.D | Patch: bump 3rd (C); Feature: bump 2nd (B) | 9.128.0.0 → 9.128.1.0 (patch) |
| Semver breaking | Major bump | | 1.10.0 → 2.0.0 |
| NPM | Semver | Feature: minor; Fix: patch | 12.54.2 → 12.55.0 |
4. Write Entry
## <version>
* BREAKING: <summary> (if any)
* Add <feature>
* Fix <bug>
5. Update Version Files
sed -i 's/^version:.*$/version: 2026.1.17.0/' package.cabal
sed -i 's/"version": "[^"]*"/"version": "12.55.0"/' package.json
6. Verify (MANDATORY)
git diff origin/master...HEAD --name-only | cut -d/ -f1-2 | sort | uniq
git diff --cached --name-only | grep -iE 'changelog'
Checklist:
7. Commit
chore: update changelogs and bump versions for <feature>
BREAKING: package-a 1.0→2.0 (<reason>)
- package-b: <summary>
- package-c: <summary>
Anti-Patterns
❌ Leading Zeros
## 2026.01.17.0 # WRONG
## 2026.1.17.0 # CORRECT
❌ Verbose Entries (>5 lines)
Condense related changes. Nobody reads 10+ line entries.
❌ Missed Packages
onping2.0/ChangeLog.md
re-react-onping-frontend/Changelog.md
❌ Manual Dates
Always use date +"%Y.%-m.%-d" — never type from memory.
❌ Blind .0 Suffix
Always check existing latest version. If today's .0 already exists, use .1, .2, etc.
Cherry-Pick & Merge Conflict Resolution
When cherry-picking or merging introduces changelog/version conflicts:
Strategy
- Keep ALL changelog entries from both sides in chronological order (newest first)
- Bump to a new version at the top — don't just pick one side's version
- Remove the cherry-pick's duplicate entries if they already appear under a different version in HEAD
.cabal versions always match the top changelog entry
Steps
git diff --name-only --diff-filter=U
grep -rn '<<<<<<\|>>>>>>>' <file>
grep -m1 '^## ' <package>/ChangeLog.md
grep '^version:' <package>/*.cabal
Example
Before (conflict in ChangeLog.md):
<<<<<<< HEAD
## 9.128.0.0
* Feature X
=======
>>>>>>> 247d901 (cherry-pick)
## 9.125.0.0
* OAuth metadata
After (resolved):
## 9.128.1.0 <-- NEW bumped version
* Re-add OAuth metadata endpoints (cherry-pick)
## 9.128.0.0 <-- HEAD entries preserved
* Feature X
## 9.125.0.0 <-- original entry in history
* OAuth metadata
Before (conflict in .cabal):
<<<<<<< HEAD
version: 9.128.0.0
=======
version: 9.125.0.0
>>>>>>> 247d901 (cherry-pick)
After (resolved — matches new changelog top):
version: 9.128.1.0
Quick Reference
date +"%Y.%-m.%-d"
grep -m1 '^## ' <package>/ChangeLog.md
git diff origin/master...HEAD --name-only | cut -d/ -f1-2 | sort | uniq
find . -maxdepth 4 -iname '*changelog*' -type f 2>/dev/null | grep -v node_modules
git log --oneline origin/master..HEAD -- <package>/
grep "^## " */ChangeLog.md
grep "^version:" */*.cabal