SachoChangelogs are for users.
An opinionated changelog manager. Release notes written by humans, kept with the code, compiled at release.
An opinionated changelog manager. Release notes written by humans, kept with the code, compiled at release.
mise use -g github:dahlia/sachonpm install -g @sacho/sachocargo install sachoSacho is a single static binary with no runtime dependencies. It works in any repository, whatever the language, and supports Git, Jujutsu, and Mercurial. Prebuilt binaries are on GitHub Releases.
Sacho is a small tool built on strong opinions about changelogs. None of them depend on Sacho: a project could follow every one with a text editor and discipline. They are worth stating before the tool is.
A changelog answers two questions for a person who already runs your software: what changed, and what should I do about it when I upgrade. It is not a development diary and not a record of effort.
Commit messages address collaborators in the vocabulary of internals. Changelog entries address users at the public surface. Tools that generate one from the other erase that distinction, and the output is a commit log arranged to look like a changelog.
An unreleased entry describes a change that exists as a commit somewhere. Kept as a file in the repository, the entry survives merges, reverts, and cherry-picks with the same guarantees the code enjoys.
A single accumulating changelog makes every pair of branches conflict at the same place. Fragments dissolve the problem: concurrent changes touch different files and merge cleanly.
A missing entry announces nothing. No test fails and no compiler complains, so checking for absence is work for a machine, and reviewers are freed to judge whether the words are any good.
A function added and renamed in the same release cycle is one change to users, not two. States that never shipped are internal history, and no commit-based generator can know that.
Every word in an entry costs every reader a moment of attention. Internal names and narrated effort tell users this document is not really for them.
Read the full argument in Philosophy.
Each user-visible change is one small Markdown file, named after the change and committed with it. Here is changes.d/clear-function.md:
- Added `clear()` to remove every entry at once.If clear() is renamed before it ships, you edit this file. Users will experience one change, and the changelog will say so.
When the release is ready, one command compiles every fragment into a dated section of CHANGES.md and deletes the consumed files:
sacho releaseVersion 1.2.0
-------------
Released on July 19, 2026.
- Added `clear()` to remove every entry at once.The released section is sealed. Sacho never rewrites it.
The release commit contains no empty unreleased section. After tagging it, sacho next 1.3.0 starts the next development cycle.
Every entry is prose written by a human at the time of the change. Sacho collects, sorts, formats, and checks; it stops before choosing the words.
Fragments follow their commits through every merge and history rewrite, so the changelog and the code cannot drift apart.
sacho check runs in hooks and CI and notices when covered source changes carry no fragment, with escape hatches for changes that genuinely need no entry.
A release compiles the fragments into a dated section and consumes them. Released sections are never touched again.
None of this requires Sacho.
A text editor and discipline are enough.
Sacho exists because discipline does not scale.
Sacho (史草) were the draft records of Joseon Korea's court historians: written as events happened, compiled into sealed annals, then washed of their ink. The name is a description of the workflow.
If Sacho earns a place in your workflow, you can support its development through GitHub Sponsors.