# 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](https://golocomotive.fr/docs/developers/releases.md).

## Example

```md
# 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 release` cuts `## Unreleased` into `## v<n> <today>`, commits and tags `v<n>`.
- At boot the app reads the released sections into its `_changelog` table. Unreleased lines never reach users.
- `GET /api/_/changelog` and the what's new modal show the releases above what each user last saw.
