clg is a small command-line tool for maintaining a Markdown CHANGELOG.md.
Instead of editing the changelog during development, record each change as a
YAML file and turn all unreleased entries into a dated release when you publish.
Warning: This project is work in progress. Use at your own risk. APIs might change. The docs are 100% AI-generated. No releases published yet.
clg uses this layout in the current working directory:
.
├── CHANGELOG.md
├── clg.yml # optional configuration
└── changelogs/
└── unreleased/
└── added-0199321f-7b2c-7c4f-bd12-4c5f8f7c2a10.yml
The files in changelogs/unreleased/ are temporary release notes. clg release
groups them by type—or by group and then type when groups are configured—inserts
the resulting Markdown into CHANGELOG.md, and removes the source files.
With Go installed:
go install github.com/hettiger/clg@latestOr build the binary from a checkout:
go build -o clg .clg requires Go 1.25.8 or newer.
Add the insertion marker to CHANGELOG.md once, usually near the top. The
default marker is <!-- CLG -->:
<!-- CLG -->Optionally configure groups, custom labels, or a different marker in clg.yml:
marker: "<!-- CLG -->"
groups:
front: Frontend
back: Backend
types:
added: New Feature
fixed: Bug FixWhen groups is configured, every entry must specify one of its keys and
releases are rendered with group headings containing type headings.
Record a change. With no flags, clg new asks for the configured group (if any),
type, and message:
clg newFor scripts or a faster workflow, provide both values directly:
clg new --type added --message "Support exporting reports"
clg new -g back -t fixed -m "Prevent duplicate notifications"Review the unreleased entries:
clg showTo show only entries recorded on a specific Git branch:
clg show --branch feature/report-exportWhen you are ready to publish, pass the release tag:
clg release v1.2.0This adds a section like the following immediately after <!-- CLG -->:
## [v1.2.0] - 2026-09-06
### New Feature (1 change)
- Support exporting reports
### Bug Fix (1 change)
- Prevent duplicate notificationsWith groups configured, the release uses one additional heading level:
### Backend
#### Bug Fix (1 change)
- Prevent duplicate notificationsThe release date is the current UTC date.
Create an unreleased changelog entry in changelogs/unreleased/.
clg new [flags]| Flag | Description |
|---|---|
-g, --group |
Configured group key. If omitted, choose from an interactive list when groups are configured. |
-t, --type |
Configured change type. If omitted, choose from an interactive list. |
-m, --message |
Entry text. If omitted, enter it interactively. |
The flags can be supplied together, which makes the command non-interactive.
clg new records the current Git branch in the entry, so it must be run from
a Git working tree. The generated filename contains the type and a UUIDv7, for
example fixed-0199321f-7b2c-7c4f-bd12-4c5f8f7c2a10.yml. When groups are
configured, the group key is prefixed to the filename, for example
back-fixed-0199321f-7b2c-7c4f-bd12-4c5f8f7c2a10.yml.
Display all valid entries that have not yet been released:
clg showThe output includes the type, title, and the Git branch associated with each
entry. Use --branch (or -b) to filter entries by branch. Group values are
shown when groups are configured and are used when generating a release. If
there are no matching entries, clg reports that there is nothing to show.
| Flag | Description |
|---|---|
-b, --branch |
Show only entries recorded on the specified Git branch. |
Convert all unreleased entries into a release and insert it into
CHANGELOG.md:
clg release v1.2.0| Flag | Default | Description |
|---|---|---|
-m, --marker |
configured marker or <!-- CLG --> |
Text where the new release is inserted. |
The marker must already exist in CHANGELOG.md. To use a different marker:
clg release v1.2.0 --marker "<!-- RELEASES -->"If there are no unreleased entries, the command leaves the changelog unchanged.
Delete all unreleased entry files:
clg cleanThe command asks for confirmation. Use --force when confirmation is not
possible or desired:
clg clean --forceThis only removes files in changelogs/unreleased/; it does not modify
CHANGELOG.md.
The following type keywords are supported:
| Keyword | Heading |
|---|---|
added |
New Feature |
fixed |
Bug Fix |
hotfix |
Hotfix |
changed |
Feature Change |
deprecated |
New Deprecation |
removed |
Feature Removal |
security |
Security Fix |
performance |
Performance Improvement |
other |
Other |
The heading is used when clg release groups entries.
Configuration is loaded from an optional clg.yml in the current working
directory. The defaults are:
marker: "<!-- CLG -->"
types:
added: New Feature
fixed: Bug Fix
hotfix: Hotfix
changed: Feature Change
deprecated: New Deprecation
removed: Feature Removal
security: Security Fix
performance: Performance Improvement
other: OtherUse groups to enable grouped releases. Group keys are used in entry files and
CLI flags; their values are the headings shown in generated Markdown:
groups:
front: Frontend
back: BackendEach entry is a YAML document. clg new writes the title, type, and current
Git branch, plus group when groups are configured:
group: back
type: changed
title: Improve report permissions
author: Jane Doe
branch: feature/report-exportThe author field is optional and is not set by clg new. The branch field
is populated automatically from the current Git branch and is used by
clg show --branch. Every YAML file in changelogs/unreleased/ must have a
non-empty title, a configured type, and—when groups are configured—a
configured group. Invalid files prevent commands that read unreleased entries
from completing.
# During development
clg new -g back -t added -m "Add CSV export"
clg new -g front -t fixed -m "Handle empty report filters"
# Review all entries, or only entries from one branch
clg show
clg show -b feature/report-export
# Before publishing
clg release v1.2.0
git diff -- CHANGELOG.md
git add CHANGELOG.md
git commit -m "Release v1.2.0"Run clg --help or clg <command> --help for the command-line help.
Run the test suite with:
go test ./...See LICENSE.