Changelog format
The grammar of an app's CHANGELOG.md, which the parser checks line by line.
CHANGELOG.md sits at the root of every app repo. The app's users read it in the what's new modal. How it is used: Changelog and releases.
Example#
# Changelog
What changes in the Orders app, newest first.
## Unreleased
- new: Export the orders as CSV.
- fix: A cancelled order no longer counts in the month's total.
## v3 2026-11-02
- change: The order list opens on this week.
## v2 2026-10-20
- Search is faster.
Grammar#
| part | rule |
|---|---|
| head | free text above the first ## section |
## Unreleased | the first section. It is empty between releases when nothing waits |
## v<n> YYYY-MM-DD | one per release, newest first: n a positive integer that goes down from top to bottom, the date a real calendar date |
| an entry | - <text>, one line per change |
| a tag | optional, lowercase, at the start of the text: new: , fix: or change: |
What the parser refuses#
Each with its line number:
- any line in a section that is not an entry (a blank line is fine);
- a release with no entry;
- versions out of order;
- a bad date.
Writing an entry#
- One entry per change a user can see, in the app's language.
- Say what the user gets, not what the code does. "Export the orders as CSV", never "add csvExport to OrdersGrid".
- No file names, no commit messages.
Where it goes#
golo releasecuts## Unreleasedinto## v<n> <today>, commits and tagsv<n>.- At boot the app reads the released sections into its
_changelogtable. Unreleased lines never reach users. GET /api/_/changelogand the what's new modal show the releases above what each user last saw.