A CLI that turns your Git history into release-ready changelogs using a local LLM.
Instead of manually sorting hundreds of commits into Added, Changed, Fixed, and other categories, Laminate reads your Git history, interprets the changes, and generates a clean Keep a Changelog compatible document.
Features
- 🤖 Local LLM processing — your Git history stays on your machine
- 📝 Release-ready Markdown — generates structured changelogs
- 🗂️ Automatic categorization — sorts changes into standard changelog categories
- 🧩 Related-commit grouping — combines related commits into a single entry
- 📦 Batch processing — process large repositories without sending the entire history to the model at once
- 🔒 No API keys required — Laminate uses a local GGUF model through
llama-cpp-python - 🛠️ Git-aware filtering — filter commits by date or Git commit range
- 🚀 Release support — generate either an
[Unreleased]section or a versioned release
Installation
PyPI
Install Laminate with pip:
pip install laminate-cli
Note: The PyPI package is named
laminate-cli, while the command and Python package are namedlaminate.
From source
Clone the repository and install it locally:
git clone https://github.com/Apleut/Laminate.git
cd Laminate
pip install .
For development:
pip install -e .
Windows
llama-cpp-python may require a pre-built CPU wheel on Windows.
Install it first with:
pip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu
Then install Laminate:
pip install .
Model
Laminate runs a local GGUF model using llama-cpp-python.
Place exactly one .gguf model file in:
models/
└── your-model.gguf
Phi-4-mini-instruct is a good pick, and is the model used for Laminate's development.
Laminate automatically finds and loads the model when it runs.
If the models/ directory does not exist, or contains zero or multiple .gguf files, Laminate will stop and explain what needs to be fixed.
The model is intentionally kept separate from the package because GGUF models can be large and have different licensing requirements.
Usage
From inside a Git repository:
laminate
Laminate will read the repository's commit history, categorize the changes, and write the result to:
CHANGELOG.md
For example:
Reading commits from working directory...
Found 42 commits. Categorizing with the local model...
[categorize] processing batch 1/3 (20 commits)...
[categorize] processing batch 2/3 (20 commits)...
[categorize] processing batch 3/3 (2 commits)...
Done. Changelog written to CHANGELOG.md
Options
--repo
Specify the Git repository to read.
laminate --repo ./my-project
Defaults to the current working directory.
--since
Only include commits after a specific date.
laminate --since 2026-01-01
--until
Only include commits before a specific date.
laminate --until 2026-10-01
--range
Process a specific Git commit range.
laminate --range v1.0.0..v1.1.0
--range overrides --since and --until.
This is particularly useful when generating a changelog for a release.
--output
Choose where the generated changelog should be written.
laminate --output RELEASE_NOTES.md
Defaults to:
CHANGELOG.md
--batch-size
Control how many commits are sent to the model at once.
laminate --batch-size 25
Larger batches can provide more context to the model, while smaller batches can reduce the amount of context required for each request.
--release
Generate a versioned release section instead of an [Unreleased] section.
laminate --release 1.1.0
The resulting header will look like:
## [1.1.0] - 2026-10-03
Without --release, Laminate generates:
## [Unreleased]
Example
Suppose your repository contains commits like:
Add user authentication
Fix crash when configuration is missing
Refactor authentication middleware
Remove deprecated login endpoint
Add password reset flow
Instead of producing one entry for every commit, Laminate can turn them into something like:
# Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog
and this project adheres to Semantic Versioning.
## [Unreleased]
### Added
- Added user authentication and password reset functionality.
### Changed
- Refactored the authentication middleware.
### Removed
- Removed the deprecated login endpoint.
### Fixed
- Fixed a crash caused by missing configuration.
The exact output depends on the Git history and the model being used.
Supported Categories
Laminate currently uses the standard Keep a Changelog categories:
- Added
- Changed
- Deprecated
- Removed
- Fixed
- Security
Categories that contain no changes are omitted from the final document.
Privacy
Laminate is designed around local processing.
Your Git history is passed to the LLM running on your own machine. Laminate does not require an OpenAI, Anthropic, or other hosted AI API.
The model you download and use is subject to its own license and terms.
Contributing
Contributions, bug reports, and ideas are welcome.
If you find a problem with Laminate, please open an issue with:
- What you were trying to do
- The command you ran
- The relevant error message
- Your Python version
- Your operating system
Or email me at me@apleut.dev.
For changes to Laminate itself, pull requests are welcome.
License
License information will be added before the first stable release.
Metadata
Release files for laminate-cli 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| laminate_cli-0.1.1.tar.gz | 24.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| laminate_cli-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.6 kB
Release files / laminate_cli-0.1.1.tar.gz
| Download URL | laminate_cli-0.1.1.tar.gz |
|---|---|
| Size | 24.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9cce19e1dde433cf10f69b6688231d8839eb543d5450d8ae0b56009ff370b332
|
|
BLAKE2b-256 checksum How to use checksums |
efa4d2b41205cc00ef2fa4ac1ba92929c8fb7ada119a5719c65b01b2f0f1b01c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / laminate_cli-0.1.1-py3-none-any.whl
| Download URL | laminate_cli-0.1.1-py3-none-any.whl |
|---|---|
| Size | 24.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d197831ddc51ccc9b8fd4c870e701d29116c730442a22e54c9243884fc09f6ab
|
|
BLAKE2b-256 checksum How to use checksums |
ba026ecfbabbbb86c0f51e66cae58f2971337620754cac7eb43d53387e2b4cf3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency log