Changelog¶
HARP maintains a changelog following the Keep a Changelog format. All changes are tracked in version-specific files in docs/changelogs/.
Overview¶
Entries are towncrier fragments: one small file per pull
request in changelog.d/, so two pull requests never edit the same file and never conflict. The
release manager assembles the fragments into docs/changelogs/X.Y.Z.rst when cutting the final
X.Y.Z. A pre-release (-alphaN, -betaN, -rcN) leaves the fragments in place: its GitHub
release notes are rendered from them, and the final release still needs them.
During development: Add a fragment to
changelog.d/in your pull requestBefore release: Build the fragments into a version-specific file (e.g.,
0.11.0.rst)After release: The version-specific changelog appears in the GitHub Release
The documentation build renders the pending fragments as the unreleased changelog page
(docs/changelogs/unreleased.rst, generated and git-ignored), titled with the version read from
pyproject.toml. Without a pending fragment, the page does not exist.
When to Add Entries¶
Add a fragment per Pull Request:
Before merging a PR, ensure
changelog.d/contains a fragment for your changesIf a PR contains multiple distinct changes, add multiple fragments
Each entry should describe what changed from a user/contributor perspective
Do NOT add entries for:
Minor typo fixes in documentation
Internal refactoring with no external impact
Dependency updates (unless they fix a critical issue)
Categories¶
Entries are organized into these categories:
- Important Changes
Breaking changes or significant modifications requiring attention.
Use this sparingly - only for changes that require action from users.
- Added
New features, capabilities, or documentation.
Examples:
Version validation in release workflow
Support for Python 3.14 free-threaded mode
New
bin/validate_versionscript
- Changed
Changes to existing functionality.
Examples:
Updated release workflow to require manual version bumps
Migrated from Poetry to UV package manager
Bump dependency:
alembic: 1.15.2 → 1.17.0
- Fixed
Bug fixes.
Examples:
Fixed race condition in transaction storage
Corrected timezone handling in dashboard
- Removed
Removed features or dependencies.
Examples:
Removed Poetry dependency
Removed deprecated
--legacyflag
How to Add an Entry¶
Create changelog.d/<issue>.<category>.rst holding the one-line entry, where <category> is
one of important, added, changed, fixed, security or removed:
echo 'Support for Python 3.14t (free-threaded/no-GIL).' > changelog.d/123.added.rst
The issue number is appended to the entry as (#123). A change without an issue uses a name
starting with + and any slug, which renders no reference: changelog.d/+python-314t.added.rst.
A second fragment for the same issue and category takes a counter: 123.added.1.rst.
Preview the result with:
uv run towncrier build --draft --version 0.11.0
Commit the fragment with your changes.
Writing Good Entries¶
Good entries are:
User-focused: Describe the impact, not the implementation
Concise: One line per change
Specific: Clear about what changed
Examples:
✅ Good:
* Added version validation to prevent tag/version mismatches
* Fixed dashboard crash when viewing large transactions
* Removed support for Python 3.11
❌ Bad:
* Updated code
* Fixed bug in src/storage/models.py line 42
* Refactored validation logic (too vague)
For breaking changes, be explicit:
Important Changes
:::::::::::::::::
* ⚠️ Release workflow now requires manual version updates in pyproject.toml
before tagging. The CI no longer modifies versions automatically.
Changelog Format¶
The assembled changelog follows this structure (empty categories are omitted):
Version 0.11.0 (2026-10-30)
===========================
Important Changes
:::::::::::::::::
- ⚠️ Breaking change description with warning emoji
Added
:::::
- New feature 1 (#123)
Changed
:::::::
- Changed behavior 1
Fixed
:::::
- Bug fix 1
Security
::::::::
- Security fix 1
Removed
:::::::
- Removed feature 1
Before Release (Release Manager)¶
The release manager performs these steps before creating a release:
Review pending fragments
Check that all entries in
changelog.d/are clear, properly categorized, and user-focused.Build the version-specific file (final release only, never for a pre-release)
# For version 0.9.0 uv run towncrier build --draft --version 0.9.0 --date 2025-01-15 > docs/changelogs/0.9.0.rst git rm changelog.d/*.*.rst
The
changelog.d/README.rstfile stays. After a patch release, the pull request that bringsX.Y.Z.rsttomainalso runsgit rmon the fragments that patch shipped, so the nextX.Y+1.0lists only what is new since. Check the first lines of the new file: theVersion X.Y.Z (date)title and its underline must come first.Update changelog index
Add the new version to
docs/changelogs/index.rst, belowunreleased:.. toctree:: :maxdepth: 1 unreleased 0.9.0 0.8.0 ...
Commit changelog updates
git add docs/changelogs/ changelog.d/ git commit -m "docs: prepare changelog for 0.9.0"
The GitHub Release workflow automatically converts the RST changelog to Markdown and includes it in the GitHub Release.
See Also¶
Python Package - Complete release process
Keep a Changelog - Changelog format specification