The CHANGELOG records every completed code change, but does not recount every file and commit. A mechanical edit gets a short entry; a decision gets context that is not in the code: why it was done this way, what came before, and what was rejected.
Scope
- Apply after every completed code change in a project where a changelog is maintained.
- Apply when setting up a changelog in a new project.
- Apply when preparing a release.
- Do not apply to commit messages, PR descriptions, or user-facing release notes — different formats, different readers.
Core Principles
- It is written for the person who will return in six months. Usually that is the author themselves, who has forgotten the context.
- Completeness does not require judging importance. The code changed — an entry appeared. One item describes a whole change, not every file or commit.
- Depth depends on the decision. For a mechanical edit, it is enough to name the area and explicitly say that behavior did not change. For a non-obvious decision, you need the reason, the previous state, and the rejected options.
- "Why" is worth more than "what". What changed is visible in the diff. Why this option was chosen is not visible anywhere.
- A changelog does not describe the current state. The current rule lives in the code, configuration, or contract; the changelog explains why it changed and points to where to find it.
- A rejected alternative is more valuable than a description of the accepted one. It will keep you from turning it back in six months and stepping on the same rake.
- The entry is made immediately, not before a release. Otherwise completeness can no longer be checked as work progresses, and the reasons for decisions are forgotten in time.
Format
File structure
# Changelog
Все заметные изменения <проект>. Формат — Keep a Changelog.
---
## [Unreleased]
### Added
### Changed
### Fixed
---
## [0.1.3] — 2026-07-31
### <Заголовок релиза — одной фразой о сути>
- **Что:** …
- **Где:** …
- **Почему:** …
- **Было:** …
### Added
### Changed
### Fixed
Release summary — four fields
The most valuable part. Not a retelling of the items below, but an answer to the question "what actually changed in the product":
| Field | What it answers |
|---|---|
| What | what now works differently, in terms of the product, not the code |
| Where | which files and areas are affected — the entry point for whoever goes digging in |
| Why | what pain this relieves; what it was all done for in the first place |
| Before | how it behaved before — otherwise in six months it's unclear what was being fixed |
The Before field is most often skipped, and for no good reason: without it the entry describes a world the reader doesn't remember.
Bullets within sections
One entry = one complete change, not one file or commit. Inside:
- bold heading — the gist in one phrase
- what changed and where
- for a mechanical edit — an explicit "behavior did not change"
- for a non-obvious decision — why it was chosen this way, how it was before, and what was rejected
Example:
Right-click instead of a hover pop-up menu. Copying a link from text moved into the context menu (
LinkContextMenu). At first it was a hover micro-menu, but the cursor didn't have time to reach the button — the context menu matches the behavior of a native text field and doesn't require rushing to do anything.
Here there is a rejected option and the reason for rejecting it. In six months this won't let it be "improved" back.
Workflow
- After each completed code change — immediately add one bullet to
[Unreleased], in the appropriate section (Added / Changed / Fixed). - Choose the depth. Record a mechanical edit as a single line noting that behavior did not change. For a behavior change or a non-obvious decision, add the reason, the previous state, and the rejected options.
- Formulate from the product's perspective, when the behavior changed: not "added a parameter" but "now you can do X".
- At release — turn
[Unreleased]into a version with a date and write a summary of the four fields.
Quality check
The completeness check is simple: if the code changed, in [Unreleased] a point about a
coherent change appeared.
For a mechanical edit, it is enough to answer:
- where it changed;
- whether it is confirmed that the behavior remained the same.
For a behavior change or a decision, the entry must answer:
- what changed for the user;
- why it was done this way and not otherwise;
- where to look at the code;
- how it was before.
If the changelog has to be used to reconstruct current values or rules — they are not there; the entry must reference the active source.
References
references/01-antipatterns.md— how not to do it, with an analysisreferences/02-examples.md— examples of entries before and after