Skip to main content

ledgr

PyPI version Python versions CI status License

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

Install from PyPI with uv:

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 as YYYY-MM-DD.
  • sections: ordered, nonempty groups with type, heading, and changes.
  • Each change has id (fragment identifier), type, bump (effective), and body (Markdown), plus prs (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)

Source distribution for ledgr 0.2.0
File Size Uploaded
ledgr-0.2.0.tar.gz 16.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ledgr 0.2.0
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page