| description | Install Lint My Headers, declare a header policy, and run your first read-only check and safe year refresh. |
|---|
Install the CLI, declare your policy, and run your first read-only check.
Install the published multilingual release or build the CLI from source.
=== "Published release"
With [uv](https://docs.astral.sh/uv/), install the native wheel:
```shell
uv tool install lint-my-headers==0.8.0
lmh --version
```
PyPI tooling requires Python 3.11+. Wheels contain native `lmh` and
`lint-my-headers` executables. Building a source distribution also requires
Rust and a C compiler. Version 0.8.0 supports all nine languages and every
[configuration container](configuration.md#configuration-files).
=== "Source checkout"
Use the pinned Rust 1.93 toolchain and a native linker:
```shell
git clone https://github.com/frgfm/lint-my-headers.git
cd lint-my-headers
cargo install --path . --locked
lmh --version
```
Ensure Cargo's binary directory is on your `PATH`. Python is optional when
using the native CLI directly.
=== "Without Python"
Download the [0.8.0 PyPI wheel](https://pypi.org/project/lint-my-headers/0.8.0/#files)
for your operating system and CPU; choose `musllinux` for Alpine. Wheels are
ZIP archives with both commands; verify their SHA-256 checksums against PyPI.
For Linux x86_64 with glibc 2.28+:
```shell
wheel=lint_my_headers-0.8.0-py3-none-manylinux_2_28_x86_64.whl
unzip -q "$wheel" -d lmh-wheel
./lmh-wheel/lint_my_headers-0.8.0.data/scripts/lmh --version
```
On Windows, rename the matching `.whl` file to `.zip`, extract it, and run
`lmh.exe` from its `.data/scripts` directory. Keep the extracted directory
intact so it retains the bundled license. Add `scripts` to `PATH` if needed.
macOS may block browser-downloaded binaries. If blocked, use the published
release installation above rather than disabling Gatekeeper.
Use your project's established ownership and license. These example values are
placeholders; the tool never infers them. Set paths to directories that exist and
keep the corresponding LICENSE at the project root.
=== "pyproject.toml"
Add this section to `pyproject.toml`:
```toml
[tool.lint-my-headers]
owner = "Example Organization"
starting-year = 2024
license = "Apache-2.0"
languages = ["python", "typescript", "rust"]
paths = ["src", "tests"]
ignore-files = ["version.py"]
ignore-folders = ["src/generated"]
```
=== ".lmh.toml"
Create `.lmh.toml` in your project root:
```toml
owner = "Example Organization"
starting-year = 2024
license = "Apache-2.0"
languages = ["python", "javascript", "typescript", "rust", "go", "swift", "bash", "c", "cpp"]
paths = ["src", "tests"]
ignore-files = ["version.py"]
ignore-folders = ["src/generated"]
```
Select only the languages used by your project. The default is Python. Both configuration examples work with the published release and source checkout.
Run from the project directory:
lmh check
lmh check src/package tests/test_api.py
lmh check --helpThe first command uses configured paths; positional paths replace that list. Checks are read-only. A valid Python header in 2026 looks like this:
# Copyright (C) 2024-2026, Example Organization.
# This program is licensed under the Apache License 2.0.
# See LICENSE or go to <https://www.apache.org/licenses/LICENSE-2.0> for full license details.Bash uses the same # marker. Other supported languages use //, with the same
text and blank lines. See header layouts for
language-specific details. The additional layouts
support common copyright lines, ordinary blocks, and single-owner SPDX pairs.
Missing-header insertion requires an explicitly declared creation year.
For a recognized header ending in 2025, lmh check reports LMH004. When the
diagnostic is marked fixable and source changes are authorized:
# Available in unreleased development builds:
lmh fix --diff
lmh fix
lmh check
git difffix --diff prints eligible repairs as unified diffs without writing source
files. The option is available only with text output and the fix command.
Exit code 1 means that the preview contains proposals or that findings remain.
Patch paths are relative to the policy root; external and non-Unicode paths
remain unresolved.
In 2026, a creation year of 2024 with an end year of 2025 becomes
2024-2026. The tool retains the creation year and every other byte. It leaves
ineligible findings for manual review.
Version 0.8.0 can insert a header when the policy supplies its owner and
notice and you declare the file's first copyright year. The existing
starting-year is a validation floor; it is not used as the file's year.
lmh check --creation-year 2024 src/new_file.py
lmh fix --creation-year 2024 src/new_file.py
lmh check src/new_file.py
git diffThe new header uses 2024 through the current year. Declare the actual year for
the selected files; creation-year = 2024 in project configuration has the same
effect. Without this declaration, fix keeps LMH001 unresolved.
Select files with the same actual creation year and run separately for different years.
Insertion keeps the original bytes, encoding, line endings, preambles, and mode. Existing legal declarations, ambiguous layouts, and notices that cannot be encoded in the file remain unfixable. Python files that start with parentheses, joined or escaped strings, or byte, formatted, or template strings also require review. Existing headers still use the limited end-year repair.
Insertion refuses any file that contains copyright, ©, SPDX, license,
licence, or all rights reserved, regardless of case or position. An attribution
such as (c) 2024 Other Owner in a leading comment or Python module docstring
also needs review. Examples and variable names can trigger these guards;
LMH001 explains the refusal. Review those files and add the header manually.
| Exit code | Meaning |
|---|---|
0 |
No unresolved findings; any eligible repairs completed. |
1 |
Unresolved findings remain. |
2 |
Invocation, configuration, or I/O failure. |
For CI, use Integrations. For programmatic output, see Diagnostics & agents.