Skip to content

Commit 7c41065

Browse files
committed
ai(claude[commands]) Add /changelog
why: Automate CHANGES entry generation from branch commits with categorization and review what: - Add .claude/commands/changelog.md with 5-phase changelog workflow - Gathers commits, categorizes by type, generates markdown entries, inserts after user review
1 parent c98a2b8 commit 7c41065

1 file changed

Lines changed: 213 additions & 0 deletions

File tree

.claude/commands/changelog.md

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
---
2+
description: Generate CHANGES entries from branch commits and PR context
3+
argument-hint: "[optional additional context about the changes]"
4+
allowed-tools: Bash(git log:*), Bash(git branch:*), Bash(git symbolic-ref:*), Bash(gh pr view:*), Bash(gh pr list:*), Read, Grep, Glob, Edit
5+
---
6+
7+
# Changelog Entry Generator
8+
9+
Generate well-formatted CHANGES entries from the current branch's commits and PR context. This command analyzes commits, categorizes them, and inserts entries into the CHANGES file after user review.
10+
11+
Additional context from user: $ARGUMENTS
12+
13+
---
14+
15+
## Phase 1: Gather Context
16+
17+
**Goal**: Collect all information needed to generate changelog entries.
18+
19+
**Actions**:
20+
21+
1. **Detect project name** from `pyproject.toml`:
22+
- Read `pyproject.toml` and extract the `name` field under `[project]`
23+
- This is used for matching the CHANGES heading format (`## <project> vX.Y.Z`)
24+
25+
2. **Detect trunk branch**:
26+
```
27+
git symbolic-ref refs/remotes/origin/HEAD
28+
```
29+
- Strip `refs/remotes/origin/` prefix to get branch name
30+
- Fall back to `master` if the above fails
31+
32+
3. **Verify not on trunk**:
33+
- Check current branch: `git branch --show-current`
34+
- If on trunk, report "Already on trunk branch — nothing to generate" and stop
35+
36+
4. **Read CHANGES file**:
37+
- Find the CHANGES file (usually `CHANGES` with no extension at project root)
38+
- Identify the unreleased section heading (e.g., `## vcspull v1.51.x (unreleased)`)
39+
- Locate the `<!-- END PLACEHOLDER` marker line — this is where new entries are inserted
40+
- Note any existing entries between `<!-- END PLACEHOLDER -->` and the next `## ` release heading
41+
- Record which section headings (e.g., `### Bug fixes`, `### Features`) already exist in the unreleased block
42+
43+
5. **Check for PR**:
44+
```
45+
gh pr view --json number,title,body,labels 2>/dev/null
46+
```
47+
- If a PR exists, extract the number, title, body, and labels
48+
- If no PR exists, note that `(#???)` placeholders will be used
49+
50+
6. **Get commits**:
51+
```
52+
git log <trunk>..HEAD --oneline
53+
```
54+
- Also get full commit details for body parsing:
55+
```
56+
git log <trunk>..HEAD --format='%H %s%n%b---'
57+
```
58+
- If no commits ahead of trunk, report "No commits ahead of trunk" and stop
59+
60+
---
61+
62+
## Phase 2: Categorize Commits
63+
64+
**Goal**: Parse commits into changelog categories and group related ones.
65+
66+
### Commit type mapping
67+
68+
Parse the commit type from the `Component(type[sub])` convention in commit subjects:
69+
70+
| Commit type | CHANGES section | Notes |
71+
|---|---|---|
72+
| `feat` | Features / New features | New functionality |
73+
| `fix` | Bug fixes | Bug fixes |
74+
| `docs` | Documentation | Doc changes |
75+
| `test` | Tests | Test additions/changes |
76+
| `refactor` | (only if user-visible) | Skip internal-only refactors |
77+
| `chore`, `deps` | Development | Maintenance, dependency bumps |
78+
| `style` | (skip) | Formatting-only changes |
79+
80+
### Grouping rules
81+
82+
- **TDD workflow sequences**: An xfail commit + a fix commit + an xfail-removal commit should collapse into a **single** bug fix entry. The fix commit's message is the primary source.
83+
- **Dependency bumps**: A `pyproject` deps commit + a CHANGES doc commit = 1 entry under "Breaking changes" (if it's a minimum version bump) or "Development"
84+
- **Multi-commit features**: Sequential `feat` commits on the same component collapse into one entry
85+
- **Skip entirely**: merge commits, `commands(feat[...])` commits (adding claude commands), lock-only changes, internal-only refactors
86+
87+
### Output of this phase
88+
89+
A structured list of entries grouped by section, each with:
90+
- Section name (e.g., "Bug fixes")
91+
- Entry text (formatted markdown)
92+
- Source commit(s) for traceability
93+
94+
---
95+
96+
## Phase 3: Generate Entries
97+
98+
**Goal**: Write the exact markdown to be inserted into CHANGES.
99+
100+
### Format rules (derived from existing CHANGES files)
101+
102+
1. **Section headings**: Use `### Section Name` (e.g., `### Bug fixes`, `### Features`)
103+
104+
2. **Section order** (only include sections that have entries):
105+
- Breaking changes
106+
- Features / New features
107+
- Bug fixes
108+
- Documentation
109+
- Tests
110+
- Development
111+
112+
3. **Simple entries** — single bullet:
113+
```markdown
114+
- Brief description of the change (#123)
115+
```
116+
117+
4. **Detailed entries** — sub-heading with description:
118+
```markdown
119+
#### Component: Brief description (#123)
120+
121+
Explanatory paragraph about what changed and why.
122+
123+
- Bullet point with specific detail
124+
- Another detail
125+
```
126+
127+
5. **PR references**:
128+
- If PR number is known: `(#512)`
129+
- If no PR exists: `(#???)`
130+
131+
6. **Match existing style**:
132+
- Check whether the project uses "Bug fixes" or "Bug Fixes" (match existing capitalization)
133+
- Check whether "Features" or "New features" is used
134+
- Preserve the project's conventions
135+
136+
### Entry writing guidelines
137+
138+
- Write from the user's perspective — what changed for them, not internal implementation details
139+
- Lead with the *what*, not the *why* (the description paragraph handles *why*)
140+
- Use present tense for the entry title ("Add support for..." not "Added support for...")
141+
- Don't repeat the section heading in the entry text
142+
- Keep bullet entries to 1-2 lines; use the sub-heading format for anything needing more explanation
143+
144+
---
145+
146+
## Phase 4: Present for Review
147+
148+
**CRITICAL**: This is a mandatory confirmation gate. Never skip to Phase 5 without explicit user approval.
149+
150+
**Present to the user**:
151+
152+
1. **Summary line**:
153+
```
154+
Branch: <branch-name> | Commits: <count> | PR: #<number> (or "none")
155+
```
156+
157+
2. **Proposed entries** in a fenced code block showing the exact markdown:
158+
````
159+
```markdown
160+
### Bug fixes
161+
162+
- Fix phantom "None" message when syncing path-based patterns (#512)
163+
164+
#### cli/sync: Report errored git syncs in summary (#512)
165+
166+
`update_repo()` now detects and reports git sync failures instead of
167+
silently succeeding. The sync summary shows errored repositories
168+
alongside successful and failed counts.
169+
```
170+
````
171+
172+
3. **Insertion point**: Describe where these entries will go:
173+
```
174+
Insert after: <!-- END PLACEHOLDER - ADD NEW CHANGELOG ENTRIES BELOW THIS LINE -->
175+
Before: (next release heading or existing unreleased entries)
176+
```
177+
178+
4. **Ask the user**: "Insert these entries into CHANGES? You can also ask me to modify them first."
179+
180+
**Wait for user response.** Do not proceed until they confirm.
181+
182+
---
183+
184+
## Phase 5: Insert into CHANGES
185+
186+
**Goal**: Insert the approved entries into the CHANGES file.
187+
188+
**Only execute after explicit user approval in Phase 4.**
189+
190+
### Insertion logic
191+
192+
1. **Find the insertion point**: Locate the `<!-- END PLACEHOLDER` line in the CHANGES file
193+
194+
2. **Check for existing unreleased section headings**:
195+
- If the CHANGES file already has a `### Bug fixes` section in the unreleased block, and the new entries also have bug fixes, **append** to the existing section rather than creating a duplicate heading
196+
- If the section doesn't exist yet, insert the full section with heading
197+
198+
3. **Insert the entries**:
199+
- Use the Edit tool to insert after the `<!-- END PLACEHOLDER -->` line
200+
- Ensure exactly one blank line between the placeholder comment and the first section heading
201+
- Ensure exactly one blank line between sections
202+
203+
4. **Show the result**:
204+
- After editing, read the modified region of the CHANGES file and display it so the user can verify
205+
- Note: this command does NOT commit — the user decides when to stage and commit the CHANGES update
206+
207+
### Edge case: merging with existing entries
208+
209+
If there are already entries below the placeholder in the unreleased section:
210+
211+
- New entries for **existing sections** are appended at the end of that section (before the next `###` heading or the next `## ` release heading)
212+
- New entries for **new sections** follow the section order defined in Phase 3 — insert the new section in the correct position relative to existing sections
213+
- Never duplicate a `###` section heading

0 commit comments

Comments
 (0)