Skip to content

Commit 274239f

Browse files
committed
[changelog] Refine changelog entries and skill guidance
1 parent 56056f3 commit 274239f

9 files changed

Lines changed: 644 additions & 472 deletions

File tree

Lines changed: 76 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,102 @@
11
---
22
name: changelog-generator
3-
description: Generate and maintain CHANGELOG.md following Keep a Changelog format with human-readable descriptions. Use when: (1) Creating initial changelog from git tags, (2) Updating changelog for new releases, (3) Generating unreleased section for pull requests. Rule: NEVER use commit messages as source of truth - analyze code diffs instead.
3+
description: Generate or refresh human-readable CHANGELOG.md files that follow Keep a Changelog by comparing git tags and code diffs instead of commit messages. Use when Codex needs to bootstrap a changelog for a repository, backfill undocumented tagged releases, update release entries, or rewrite the Unreleased section for current branch work using the phly/keep-a-changelog commands available in the project.
44
---
55

66
# Changelog Generator
77

8-
Generates and maintains CHANGELOG.md following the Keep a Changelog format with clear, specific, and self-sufficient descriptions.
8+
Generate changelog entries that a reader can understand without opening the code.
99

10-
## Dependencies
10+
## Deterministic Helpers
1111

12-
- `phly/keep-a-changelog` - Installed in project
13-
- Git - For analyzing code changes
14-
- GitHub CLI (`gh`) - For reading PR context
15-
- Filesystem - For reading/writing CHANGELOG.md
12+
Use the bundled PHP scripts before manual analysis:
1613

17-
## PR Context Integration
18-
19-
When generating changelog for changes that belong to a PR:
20-
21-
1. Detect PR reference: Check git branch name or recent PR comments
22-
2. Fetch PR description: Use `gh pr view <pr-number> --json body`
23-
3. Extract context: Read the PR Summary and Changes sections
24-
4. Enhance descriptions: Use PR context to write more accurate changelog entries
25-
26-
Example workflow:
2714
```bash
28-
# Detect current PR
29-
BRANCH=$(git branch --show-current)
30-
PR_NUM=$(echo "$BRANCH" | grep -oE '[0-9]+' | head -1)
31-
32-
# Fetch PR context if exists
33-
if [ -n "$PR_NUM" ]; then
34-
PR_BODY=$(gh pr view "$PR_NUM" --json body --jq '.body')
35-
# Use PR body as an extra context to define the changelog descriptions
36-
fi
15+
php .agents/skills/changelog-generator/scripts/changelog-state.php
16+
php .agents/skills/changelog-generator/scripts/diff-inventory.php <from-ref> <to-ref>
3717
```
3818

39-
This ensures changelog descriptions align with the PR intent and provide better context.
40-
41-
## Key Commands
19+
- `changelog-state.php` reports changelog presence, documented versions, discovered tags, undocumented tags, and suggested release ranges as JSON.
20+
- `diff-inventory.php` reports changed files, line counts, and likely user-visible paths for a specific diff range as JSON.
21+
- Both scripts auto-discover the repository root and opportunistically load `vendor/autoload.php` when it exists.
22+
23+
## Workflow
24+
25+
1. Establish current state.
26+
- Read `CHANGELOG.md` if it exists.
27+
- Prefer `changelog-state.php` to gather versions and ranges before inspecting files manually.
28+
- Record documented versions and whether `## Unreleased - TBD` already exists.
29+
- List tags in ascending semantic order with `git tag --sort=version:refname`, and capture their commit dates when the repository may have retroactive or out-of-sequence tags.
30+
- Treat commit messages as navigation hints only; never derive final changelog text from them.
31+
32+
2. Choose diff ranges.
33+
- If `CHANGELOG.md` is missing or empty, analyze each tag range from the first tagged version onward.
34+
- If `CHANGELOG.md` already documents releases, start at the first tag after the last documented version.
35+
- When tag publication order differs from semantic order, prefer the actual tag chronology for release ordering and use diffs that follow that real release sequence.
36+
- Build `Unreleased` from the diff between the latest documented release or tag and `HEAD`.
37+
38+
3. Analyze changes from diffs.
39+
- Prefer `diff-inventory.php <from> <to>` first so you can focus on the files most likely to affect user-visible behavior.
40+
- Start with `git diff --name-status <from> <to>` and `git diff --stat <from> <to>`.
41+
- Open targeted `git diff --unified=0 <from> <to> -- <path>` views for files that define public behavior, commands, config, schemas, workflows, or exposed APIs.
42+
- Classify entries by observed impact:
43+
- `Added`: new files, APIs, commands, options, configuration, workflows, or user-visible capabilities
44+
- `Changed`: modified behavior, signature or default changes, renamed flows, or compatibility-preserving refactors with visible impact
45+
- `Fixed`: bug fixes, validation corrections, edge-case handling, or broken workflows
46+
- `Removed`: deleted APIs, commands, config, or capabilities
47+
- `Deprecated`: explicit deprecation notices or migration paths
48+
- `Security`: hardening or vulnerability fixes
49+
- Skip pure churn that a reader would not care about unless it changes behavior or release expectations.
50+
- Deduplicate multiple file changes that describe the same user-visible outcome.
51+
52+
4. Write human-readable entries.
53+
- Write one line per change.
54+
- Prefer the functional effect over implementation detail.
55+
- Mention the concrete command, class, option, workflow, or API when that improves comprehension.
56+
- When a matching PR exists, append it to the line in the format `(#123)` after the diff already supports the entry.
57+
- Avoid vague phrases such as `misc improvements`, `refactorings`, or `code cleanup`.
58+
59+
5. Apply changes with project tooling.
60+
- Prefer the local wrappers when available:
4261

4362
```bash
44-
vendor/bin/changelog # Main CLI
45-
vendor/bin/changelog add:entry # Add entry to version
46-
vendor/bin/changelog release # Create release
63+
composer dev-tools changelog:init
64+
composer dev-tools changelog:check
4765
```
4866

49-
## Execution Pipeline (Deterministic)
50-
51-
### Stage 1: Initial State
52-
53-
1. Check if CHANGELOG.md exists and has content:
54-
```bash
55-
ls -la CHANGELOG.md 2>/dev/null || echo "NO_FILE"
56-
```
57-
58-
### Stage 2: Version Discovery
59-
60-
1. List all tags sorted semantically:
61-
```bash
62-
git tag --sort=-version:refname
63-
```
64-
65-
2. Identify:
66-
- Last documented version in CHANGELOG
67-
- Tags not yet documented
68-
69-
### Stage 3: Historical Content Generation
70-
71-
**Case A: No CHANGELOG or Empty**
72-
73-
For each tag (ascending order):
74-
1. Calculate diff between current tag and previous tag (or first commit for initial version)
75-
2. Analyze code diff to infer changes (NOT commit messages)
76-
3. Group changes by type (Added, Changed, Fixed, Removed, Deprecated, Security)
77-
4. Insert version section
78-
79-
**B: Existing CHANGELOG**
80-
81-
1. Identify last documented version
82-
2. For each subsequent tag:
83-
- Generate diff between versions
84-
- Insert new section in changelog
85-
86-
### Stage 4: Unreleased Section
87-
88-
1. Calculate diff between last documented tag and HEAD
89-
2. Generate [Unreleased] section with current changes
90-
91-
## Change Classification (Inferred from Diff)
92-
93-
Analyze actual code changes, NOT commit messages:
94-
95-
| Pattern | Category |
96-
|---------|----------|
97-
| New files, new classes, new methods | Added |
98-
| Behavior changes, refactors, signature changes | Changed |
99-
| Bug fixes, validation fixes | Fixed |
100-
| Deleted classes, removed methods | Removed |
101-
| @deprecated markers | Deprecated |
102-
| Security patches | Security |
103-
104-
## Quality Rules
105-
106-
- **SHORT**: One line per change
107-
- **SPECIFIC**: Include class/method names
108-
- **SELF-SUFFICIENT**: Understand without reading code
109-
- **FUNCTIONAL**: Describe impact, not implementation
110-
- **PR-AWARE**: Use PR description to enhance accuracy when available
111-
112-
Good: "Added `Bootstrapper::bootstrap()` to create CHANGELOG.md when missing"
113-
Bad: "Add bootstrap command"
114-
115-
## PR Context Usage
116-
117-
When a PR number is available:
118-
119-
1. Read PR description for implementation intent
120-
2. Extract key capabilities mentioned in Summary
121-
3. Use specific feature names from the PR to write accurate descriptions
122-
4. Reference PR in changelog: "Added changelog automation (#40)"
123-
124-
## Integration with keep-a-changelog
125-
126-
Use CLI commands when possible:
67+
- Use the official CLI for entries and releases:
12768

12869
```bash
129-
# Add unreleased entry
130-
vendor/bin/changelog add:entry --unreleased --type=added "Description"
70+
vendor/bin/keep-a-changelog entry:added "..."
71+
vendor/bin/keep-a-changelog entry:changed "..."
72+
vendor/bin/keep-a-changelog entry:fixed "..."
73+
vendor/bin/keep-a-changelog unreleased:create --no-interaction
74+
vendor/bin/keep-a-changelog unreleased:promote 1.2.0 --date=2026-04-12 --no-interaction
75+
vendor/bin/keep-a-changelog version:show 1.2.0
76+
vendor/bin/keep-a-changelog version:release 1.2.0 --provider-token=...
77+
```
13178

132-
# Add release entry
133-
vendor/bin/changelog add:entry 1.0.0 --type=added "Description"
79+
- For large historical backfills, direct markdown editing is acceptable for the first draft. After that, use the CLI to keep `Unreleased` and future entries consistent.
13480

135-
# Create release
136-
vendor/bin/changelog release 1.0.0 --date="2026-04-11"
137-
```
81+
6. Verify the result.
82+
- Keep `Unreleased` first and released versions in reverse chronological order.
83+
- Keep section order as `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`.
84+
- Do not duplicate the same change across sections or versions.
85+
- Ensure every documented version maps to a real tag or intentional unreleased state.
86+
- Run local helpers such as `composer dev-tools changelog:check` when the project provides them.
87+
88+
## PR Context
13889

139-
Edit CHANGELOG.md directly if CLI insufficient.
90+
Use PR descriptions, issue text, or release notes only to refine wording after diff analysis confirms the change. Good uses:
14091

141-
## Verification
92+
- naming a feature exactly as presented to users
93+
- adding a stable reference like `(#123)`
94+
- understanding why a visible change matters when the diff alone is ambiguous
14295

143-
Valid changelog MUST have:
144-
- All sections: Added, Changed, Deprecated, Removed, Fixed, Security
145-
- No "Nothing." placeholders (unless truly empty)
146-
- Reverse chronological order (newest first)
147-
- [Unreleased] at top when applicable
96+
Do not use PR text to invent entries that are not supported by the code diff.
14897

14998
## Reference Files
15099

151-
- [references/keep-a-changelog-format.md](references/keep-a-changelog-format.md) - Format spec
152-
- [references/change-categories.md](references/change-categories.md) - Classification guide
153-
- [references/description-patterns.md](references/description-patterns.md) - Human-readable patterns
100+
- Read [references/keep-a-changelog-format.md](references/keep-a-changelog-format.md) for heading format, section order, and CLI mapping.
101+
- Read [references/change-categories.md](references/change-categories.md) when the diff spans multiple change types.
102+
- Read [references/description-patterns.md](references/description-patterns.md) when the first draft still sounds too internal or vague.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
interface:
22
display_name: "Fast Forward Changelog Generator"
3-
short_description: "Generate and maintain Keep a Changelog entries"
4-
default_prompt: "Use $changelog-generator to create CHANGELOG.md from git tags"
3+
short_description: "Generate changelog entries from Git diffs"
4+
default_prompt: "Use $changelog-generator to generate or refresh CHANGELOG.md from git tags, code diffs, and current unreleased work."

.agents/skills/changelog-generator/references/change-categories.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Infer category from code patterns, NOT from commit messages.
1212
- New configuration options
1313
- New CLI commands
1414
- New public APIs
15+
- New workflows or automation files
16+
- New user-visible documentation pages that introduce a capability
1517

1618
**Examples:**
1719
- `+class Bootstrapper` → "Added `Bootstrapper` class for changelog bootstrapping"
@@ -25,6 +27,7 @@ Infer category from code patterns, NOT from commit messages.
2527
- Changed default values
2628
- Behavior modifications
2729
- Refactors that affect the public API
30+
- Workflow or release process changes that alter contributor expectations
2831

2932
**Examples:**
3033
- `function foo($bar)``function foo($bar, $baz = null)` → "Changed `foo()` to accept optional `$baz` parameter"
@@ -37,6 +40,7 @@ Infer category from code patterns, NOT from commit messages.
3740
- Validation improvements
3841
- Edge case handling
3942
- Error handling corrections
43+
- Broken automation or CI repairs
4044

4145
**Examples:**
4246
- Empty input validation, null checks → "Fixed handling of null input in `parse()`"
@@ -48,6 +52,7 @@ Infer category from code patterns, NOT from commit messages.
4852
- Deleted classes
4953
- Deleted methods
5054
- Deleted configuration options
55+
- Removed commands or workflows
5156

5257
**Examples:**
5358
- `-class LegacyParser` → "Removed deprecated `LegacyParser` class"
@@ -58,6 +63,7 @@ Infer category from code patterns, NOT from commit messages.
5863
**Patterns:**
5964
- @deprecated annotations
6065
- Deprecation notices in code
66+
- Migration warnings that keep the old surface available for now
6167

6268
**Examples:**
6369
- `@deprecated` → "Deprecated `LegacyParser`, use `MarkdownParser` instead"
@@ -68,7 +74,24 @@ Infer category from code patterns, NOT from commit messages.
6874
- Security patches
6975
- Vulnerability fixes
7076
- Input sanitization
77+
- Permission hardening or secret-handling fixes
7178

7279
**Examples:**
7380
- XSS fixes → "Fixed XSS vulnerability in user input"
74-
- CSRF protection → "Added CSRF protection to form handling"
81+
- CSRF protection → "Added CSRF protection to form handling"
82+
83+
## Tie-breakers
84+
85+
When a change could fit multiple categories, prefer the most specific outcome:
86+
87+
1. `Security` over every other category
88+
2. `Removed` when the old surface is actually gone
89+
3. `Deprecated` when the old surface still exists but has a migration path
90+
4. `Fixed` for bug repairs, even if files or methods were added to implement the fix
91+
5. `Added` for genuinely new capability
92+
6. `Changed` as the fallback for user-visible behavior shifts
93+
94+
## Skip or compress
95+
96+
- Skip purely internal renames, file moves, or test-only churn unless they change behavior or contributor workflow.
97+
- Compress multiple file edits into one entry when they describe the same visible outcome.

.agents/skills/changelog-generator/references/description-patterns.md

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44

55
Rule: Describe the IMPACT, not the IMPLEMENTATION.
66

7-
## Quality Criteria
7+
## Checklist
88

9-
| Criterion | Good | Bad |
10-
|-----------|------|-----|
11-
| Specific | "Added `ChangelogCheckCommand` to verifies that the changelog contains pending unreleased notes." | "Added new feature" |
12-
| Short | One line | Paragraph |
13-
| Self-sufficient | "Creates CHANGELOG.md with all current version released" | "Bootstrap support" |
14-
| Actionable | "Added `--filter` option on TestsCommand to be able to filter test pattern classes" | "Improved CLI" |
9+
- Keep each entry to one line.
10+
- Name the surface that changed: class, command, option, workflow, API, or config.
11+
- Describe the user-visible effect first.
12+
- Avoid implementation verbs such as `extract`, `rename`, `refactor`, or `reorganize` unless the refactor itself changes behavior.
1513

1614
## Transformation Examples
1715

@@ -22,7 +20,7 @@ Bad: "feat: add bootstrap"
2220
Good: "Added `Bootstrapper` class to create CHANGELOG.md when missing"
2321
2422
Bad: "refactor: extract to new class"
25-
Good: "Extracted `CommitClassifier` for improved separation of concerns"
23+
Good: "Changed changelog generation to classify release entries by observed diff impact"
2624
2725
Bad: "fix: validate unreleased notes"
2826
Good: "Fixed validation of unreleased changelog entries"
@@ -31,34 +29,38 @@ Bad: "chore: update dependencies"
3129
Good: N/A - Skip infrastructure-only changes
3230
```
3331

34-
## Class Names Pattern
32+
## Description templates
3533

36-
Always include class/method names:
34+
Use these patterns when they fit the diff:
3735

3836
```markdown
39-
- Added `Bootstrapper` to bootstrap changelog assets
40-
- Added `MarkdownRenderer::render()` for generating output
41-
- Changed `Config::load()` to accept optional path parameter
42-
- Fixed `Parser::parse()` handling of empty input
37+
- Added `<surface>` to `<do what>` for `<benefit>`
38+
- Changed `<surface>` to `<new behavior>`
39+
- Fixed `<failure mode>` in `<surface>`
40+
- Removed deprecated `<surface>`
41+
- Deprecated `<surface>`; use `<replacement>`
4342
```
4443

45-
## API Changes Pattern
44+
## Concrete examples
4645

4746
```markdown
48-
- Added `CommandInterface::execute()` method
49-
- Changed `Parser::parse($input)` to accept optional `$options` array
47+
- Added `changelog:init` to bootstrap `.keep-a-changelog.ini` and `CHANGELOG.md`
48+
- Changed changelog sync to install reusable release-note workflows
49+
- Fixed bootstrap of the `Unreleased` section for existing changelog files
5050
- Removed deprecated `LegacyCommand`
51-
- Deprecated `Parser::process()`, use `Renderer::render()` instead
51+
- Deprecated `Parser::process()`; use `Renderer::render()` instead
5252
```
5353

54-
## Reference Patterns (PR)
54+
## Optional references
5555

56-
When changes came from a PR:
56+
Append issue or PR references only when they add useful context and the diff already supports the entry:
5757

5858
```markdown
59-
- Added changelog automation (#28)
59+
- Added changelog automation (#40)
6060
- Changed workflow to use PHP 8.3 (#31)
6161
- Fixed validation bug (#42)
6262
```
6363

64-
This helps users find more context in PR history.
64+
When a matching pull request exists, prefer appending the PR reference in the format `(#123)` at the end of the line.
65+
66+
Do not rely on the PR text as the source of truth.

0 commit comments

Comments
 (0)