ledgr
Record changes alongside your code, then combine them into a changelog and
semantic version bump. Ledgr supports single-package projects with stable X.Y.Z
versions; prereleases, build metadata, and monorepo coordination aren't supported yet.
Install
uv tool install ledgr
Requires Python 3.11 or newer. Upgrade with uv tool upgrade ledgr.
Quick start
In your project's root directory, initialize Ledgr using the version in
pyproject.toml or package.json:
ledgr init
Without an existing version file, use ledgr init --initial-version 0.1.0 instead.
If you already have a CHANGELOG.md, first add <!-- ledgr releases --> once
above its latest release. Ledgr preserves the introduction and previous releases.
Record changes, preview the next release, then apply it:
ledgr add feature "Add CSV export"
ledgr add bugfix "Handle empty configuration files"
ledgr status # Show pending entries and the proposed version
ledgr check # Validate configuration, entries, archives, and template
ledgr release --dry-run # Preview without changing files
ledgr release
Commit pending entries with their code changes. After a release, review and commit the updated version, changelog, archive, and deleted entries. Ledgr never commits, tags, pushes, publishes, or updates package lockfiles.
Entries and change types
Each entry is a Markdown file with YAML front matter in .ledgr/changes/, named
with a generated ID:
---
type: breaking
---
Replace API-key authentication with OAuth.
Create an OAuth client in Settings and pass its access token instead.
type is required; bump and prs are optional. An omitted bump inherits the current
configuration; an explicit bump stays fixed. Everything after the closing ---
is Markdown.
Run ledgr add for interactive prompts. To create and edit an entry, set $VISUAL
or $EDITOR and use --edit ($VISUAL takes precedence):
ledgr add feature --edit
Write the description directly in the editor, or pass one to prefill it. An empty body cancels the entry; invalid metadata or editor failures keep the draft for recovery.
Add PR links with --pr https://github.com/owner/repo/pull/42 (repeat for multiple
PRs), or edit the prs list in the entry's YAML front matter.
| Type | Changelog heading | Default bump |
|---|---|---|
breaking |
Breaking changes | major |
feature |
Features | minor |
bugfix |
Bug fixes | patch |
docs |
Documentation | none |
other |
Other changes | none |
Choose breaking for incompatible changes. Customize types in
configuration, or override one entry's bump:
ledgr add other "Update certificates" --bump patch
Releases
The largest pending bump determines the next version. Before 1.0.0, a major bump
becomes a minor bump by default. Use ledgr release --version 1.0.0 to move to stable,
or set pre-1-0 = false for literal major/minor/patch bumps.
Entries with bump none still appear in the changelog. If all pending entries use
none, choose ledgr release --bump patch or an explicit --version X.Y.Z.
--bump accepts patch, minor, or major. A release must have pending entries,
increase the version, and meet the minimum bump required by those entries.
release validates and renders, saves .ledgr/releases/<version>.json, updates
the version and changelog, then removes consumed entries. Archives preserve entry
text, IDs, types, effective bumps, headings, and the release date; existing archives
are never overwritten.
Run one release process at a time. Ordinary I/O failures trigger rollback, but releases aren't crash-proof transactions. If rollback fails, the archive remains for recovery.
Render archived releases
Render archived releases to stdout, newest version first, using the current template and original release dates:
ledgr render > CHANGELOG.preview.md
Unlike normal releases, rendering excludes custom introductions, manual edits, and unarchived history, as well as pending entries. Review the output before replacing your changelog.
Configuration
ledgr init creates ledgr.toml. Alternatively, place the same settings under
[tool.ledgr] in pyproject.toml. Configuration is discovered from the current
directory upward; file paths are relative to the configuration file.
If both configurations exist in a directory, Ledgr reports an error. Select one
explicitly with ledgr --config path/to/ledgr.toml status (before the command).
# ledgr.toml
version-file = "pyproject.toml"
version-key = "project.version"
# Optional settings (defaults shown):
changes = ".ledgr/changes"
releases = ".ledgr/releases"
changelog = "CHANGELOG.md"
pre-1-0 = true
# template = ".ledgr/release.md.j2"
[types.docs]
bump = "patch" # Override a built-in type
[types.security]
heading = "Security"
bump = "patch" # Custom types require a bump
Overrides merge with the five built-in types. Built-in sections retain their order; custom types follow in configuration order. Empty sections are omitted.
Version files
The configured file determines the current version, not the changelog.
| File | version-file example |
version-key example |
|---|---|---|
| TOML | pyproject.toml |
project.version |
| JSON | package.json |
version |
| Plain text | VERSION |
Omit |
For a custom location, pass --version-file and, for TOML/JSON, --version-key
to ledgr init. TOML/JSON version fields must already exist. --initial-version
creates a missing plain-text file without overwriting an existing one.
TOML comments and formatting are preserved. JSON is rewritten with two-space indentation, preserving other field values. Plain-text files contain only the version. Dotted keys address nested tables/objects, not literal dots in names or arrays.
Custom templates
Set template = ".ledgr/release.md.j2" in your configuration to use a custom
Jinja2 template. Templates render one release and receive:
version: the target version string.date: the local release date asYYYY-MM-DD.sections: ordered, nonempty groups withtype,heading, andchanges.- Each change has
id(fragment identifier),type,bump(effective), andbody(Markdown), plusprs(a list of URLs, empty when absent).
Example .ledgr/release.md.j2:
## v{{ version }} ({{ date }})
{% for section in sections %}
### {{ section.heading }}
{% for change in section.changes %}
- {{ change.body | indent(2) }}
{% endfor %}{% endfor %}
Template changes affect future releases unless you regenerate the changelog with
ledgr render; they don't affect version bumps. Unknown variables and invalid
syntax cause errors. Templates are trusted project code, not sandboxed—review
them before use.
Release files for ledgr 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ledgr-0.2.0.tar.gz | 16.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ledgr-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.1 kB
Release files / ledgr-0.2.0.tar.gz
| Download URL | ledgr-0.2.0.tar.gz |
|---|---|
| Size | 16.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6791cd5b1592823637ea8a42148f57cebe99a21570f3384b1c479b6dde099161
|
|
BLAKE2b-256 checksum How to use checksums |
e55387b1e14c639c7c62662d97585bc90442f81b8f60975d7d652a026e08025d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / ledgr-0.2.0-py3-none-any.whl
| Download URL | ledgr-0.2.0-py3-none-any.whl |
|---|---|
| Size | 19.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7845d3f48d850d782797e9f0cab50a90be41e30c7aec660cd0c8a080a206431a
|
|
BLAKE2b-256 checksum How to use checksums |
9e39824c1a74df8b19c520cbe7147a22ffe214ef25299ee3a92a44d3de906626
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|