Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Lint My Headers

A Rust CLI that checks Python copyright/license headers and safely refreshes recognized stale years. It never chooses ownership or licensing, inserts missing headers, or claims legal/SPDX/REUSE compliance.

Quick start

Install a published release, or build this checkout with Rust 1.93:

uv tool install lint-my-headers
# From source:
cargo build --release --locked

PyPI wheels contain native lmh and lint-my-headers executables; source distributions require Rust. Python 3.11+ is needed only for PyPI tooling and the optional launchers. python -m lint_my_headers replaces Python with the native process on Unix; Windows starts a child process. The callable main(argv) always returns the child's exit code. Checking and fixing run entirely in Rust.

Declare the policy in pyproject.toml:

[tool.lint-my-headers]
owner = "Example Organization"
starting-year = 2024
license = "Apache-2.0"
paths = ["src", "tests"]
ignore-files = ["version.py"]
ignore-folders = ["src/generated"]
lmh check                              # Read-only; configured paths
lmh check src/package tests/test_api.py # Explicit paths
lmh fix                                # Safe stale-year repairs only
lmh --version
lmh check --help

A valid header in 2026:

# 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.

Diagnostics name the location, reason, and repair eligibility:

src/example.py:1:1: LMH004 copyright year ends at 2025; expected 2026 [fixable]

Exit codes: 0 clean, 1 unresolved findings, 2 invocation/configuration/I/O error. fix preserves the creation year and changes no other bytes. Unknown, missing, malformed, duplicate, wrong-owner, or future-dated headers require manual review.

Configuration and safety

CLI policy options override configuration; --config selects another pyproject.toml. Configured paths are relative to that file; explicit CLI paths are relative to the invocation directory.

Key / CLI option Meaning and default
owner / --owner Required exact single-line copyright owner.
starting-year / --starting-year Required earliest accepted file creation year.
license / --license SPDX identifier selecting a prose notice; requires local LICENSE.
license-notice / --license-notice Custom notice file; configure exactly one license source.
paths / positional paths Selected files or directories; default ..
ignore-files / --ignore-files Exact basenames; default __init__.py.
ignore-folders / --ignore-folders Excluded subtrees; default .github.

CLI ignore lists are comma-separated; configuration lists are TOML arrays. Exclusions also apply to explicit inputs. Diagnostics use sorted, project-relative / paths, including .. for explicitly selected external files.

Python shebangs, UTF-8 BOMs, and PEP 263 cookies are preserved. Verified encodings are UTF-8, ASCII, Latin-1, and Windows-1252; other codecs fail without repair. Ambiguous newer Python string syntax also fails closed.

Directory discovery skips symlinks/reparse points. Explicit linked files may be checked, but repairs refuse symlinks, linked parents, reparse points, and multiple hard links. Before atomic replacement, file identity and contents are revalidated; the repaired bytes must pass the same parser.

The bundled SPDX snapshot is v3.28.0. All previously accepted v3.17 names/URLs remain valid, including the legacy KiCad-libraries-exception. Compound SPDX expressions and new exception semantics are unsupported.

Agents and JSON

Use lmh check --output-format json. Successfully parsed JSON-mode commands write only JSON to stdout; malformed CLI syntax remains a stderr usage error.

{
  "schema_version": 1,
  "tool_version": "0.6.0",
  "command": "check",
  "config_path": "pyproject.toml",
  "checked": 1,
  "changed": [],
  "diagnostics": [
    {
      "path": "src/example.py",
      "line": 1,
      "column": 1,
      "code": "LMH004",
      "message": "copyright year ends at 2025; expected 2026",
      "fixable": true
    }
  ],
  "expected_header": "# Copyright (C) <FILE_CREATION_YEAR>-2026, Example Organization.\n...",
  "error": null
}
Code Meaning
LMH001 Missing header
LMH002 Owner mismatch
LMH003 Invalid, reversed, future, or out-of-policy year
LMH004 Recognized stale year; repairable only when fixable is true
LMH005 Missing/mismatched license notice
LMH006 Malformed, misplaced, duplicated, or ambiguous layout
LMH007 Unsupported encoding or invalid bytes
LMH008 Unsafe or concurrently changed repair target
LMH900 Command/configuration/I/O error, in error rather than diagnostics

Copy this instruction into an agent task:

Read the declared owner, starting year, license, and paths; ask if any are missing.
Run lmh check --output-format json. Exit 1 means findings; exit 2 means stop.
Only run lmh fix when source changes are authorized, then recheck and inspect the
targeted diff. Never infer legal facts or install, commit, or push without permission.

The optional agent skill uses this same contract. Its retained model-evaluation results are historical Python-era evidence, not Rust evaluations.

Integrations

For pre-commit or prek, install a published wheel in the hook's isolated Python 3.11+ environment. Replace <RELEASE_VERSION> with an exact published version; --only-binary prevents an unexpected Rust build:

repos:
  - repo: local
    hooks:
      - id: lmh
        name: Lint My Headers
        entry: lmh check
        language: python
        types: [python]
        additional_dependencies:
          - --only-binary=lint-my-headers
          - lint-my-headers==<RELEASE_VERSION>

To test an unreleased checkout instead, the first-party source hook remains available:

repos:
  - repo: https://github.com/frgfm/lint-my-headers
    rev: <TAG_OR_IMMUTABLE_SHA>
    hooks:
      - id: lmh

The source hook compiles Rust on first installation with the pinned toolchain. Pre-commit's Rust installer does not pass --locked; the Action's source mode does.

Pull-request CI can run the same hook or the GitHub Action:

steps:
  - uses: actions/checkout@v7
  - uses: frgfm/lint-my-headers@<RELEASE_TAG_OR_SHA>

The Action reads repository policy; its documented inputs override it. By default it uses uv to install the exact PyPI version declared by the Action ref, with source builds disabled. version: '0.6.0' can select an exact published version; version: source explicitly builds the checked-out Action code using Cargo.lock. Floating versions, missing releases, and unavailable wheels fail rather than falling back to a compiler. Prefer immutable release SHAs. Until publication, use source mode for local/unreleased refs; the wheel recipes above are release-gated, not claims that v0.6 is already on PyPI.

Action outputs are compact JSON arrays: issues contains unresolved paths; changed contains completed writes. On exit 2, issues stays [], while changed retains any completed repairs.

The optional January 1 workflow opens or updates one reviewable year-refresh PR. It never writes directly to protected main.

Maintenance

See CONTRIBUTING.md for checks and RELEASE_NOTES.md for the breaking rename and publication gates. Runtime logic is Rust; the Python package contains only launchers and source data. Licensed under Apache-2.0.

Metadata

Release files for lint-my-headers 0.6.0rc1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lint-my-headers 0.6.0rc1
File Size Uploaded
lint_my_headers-0.6.0rc1.tar.gz 117.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for lint-my-headers 0.6.0rc1
File
lint_my_headers-0.6.0rc1-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
lint_my_headers-0.6.0rc1-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
lint_my_headers-0.6.0rc1-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
lint_my_headers-0.6.0rc1-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details
lint_my_headers-0.6.0rc1-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details
lint_my_headers-0.6.0rc1-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details
lint_my_headers-0.6.0rc1-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
lint_my_headers-0.6.0rc1-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 21.6 MB

Release files / lint_my_headers-0.6.0rc1.tar.gz

Download URL lint_my_headers-0.6.0rc1.tar.gz
Size 117.8 kB
Tags Source
SHA-256 checksum
How to use checksums
69da05b298212a3b62acc785d77ecfdfc6c22b210e8713258807949d27defc16
BLAKE2b-256 checksum
How to use checksums
1c85b953b172b3e238ded17fd9964e9641bfa00baca42eb0b3588340b8b1b5d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-win_arm64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-win_arm64.whl
Size 2.5 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
55c8927ce049cf1c6c5170da3c8742c5463a000a833c3f97e4ba90406730477e
BLAKE2b-256 checksum
How to use checksums
712590fb9134e982456a1a2c872a50951409183ad6902592554920a382966b89
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-win_amd64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-win_amd64.whl
Size 2.6 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
b147d0e9662af7033326a48bf40bab322d19637ed64f598fe5ca7422541eca76
BLAKE2b-256 checksum
How to use checksums
7792141f5a4853807450a9a39c7648383b5214965ccab2e9c7a85e96b6f272aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-musllinux_1_2_x86_64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-musllinux_1_2_x86_64.whl
Size 3.0 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
9621b1bdb1e6fbdbaae3e9d5e8c24ffda95530ee5d8bb2d5bfbae6c0a45af6c9
BLAKE2b-256 checksum
How to use checksums
3e0bf4204691640ecd929d95f048a0689f2f7ae1020a14ea6f2bed8497726315
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-musllinux_1_2_aarch64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-musllinux_1_2_aarch64.whl
Size 2.7 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
bcafb207000b28aacedc936c323f2374d90fcbd0a290ed92d6556be109f8e9d5
BLAKE2b-256 checksum
How to use checksums
6abcfef679e98775cb68f08f2b841758e7b0935dba1e237ef999fab406338cc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-manylinux_2_28_x86_64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-manylinux_2_28_x86_64.whl
Size 2.8 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
40831d08d963659e43d2a6b06869e999c8485003ab4879e8a6fbc62fff1ec1c1
BLAKE2b-256 checksum
How to use checksums
4f1c95e44a26cc9b117df532582f839a1fd419ac3a79648dc4a26af4be094ca9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-manylinux_2_28_aarch64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-manylinux_2_28_aarch64.whl
Size 2.7 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
cee6413b835de2cb31956719b83248bf473e0485da7a0cacb114c32f5ed381d5
BLAKE2b-256 checksum
How to use checksums
e40207a327f6e51b350026906950191826a527647764786d3ff88e872c52e879
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-macosx_11_0_arm64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-macosx_11_0_arm64.whl
Size 2.6 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
6baceff9d7eff1cdd9aa3355393011f991ede4f80913bfd97e44d08a4ef92e39
BLAKE2b-256 checksum
How to use checksums
7724a0b01afd70d649327f69538e5dd945f4e959b396d21d5ece9994ebbef066
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / lint_my_headers-0.6.0rc1-py3-none-macosx_10_12_x86_64.whl

Download URL lint_my_headers-0.6.0rc1-py3-none-macosx_10_12_x86_64.whl
Size 2.7 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
02afeabb0046f5d04e97ff046246b7d9bbf48d440899f48d47895c11396e727a
BLAKE2b-256 checksum
How to use checksums
0c0b4e3aa44a1b206dfeba08bef111980d8302cd7fcf6d34cc155219f0bdf155
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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

0.7.0

9 release files

0.6.0

9 release files

This release

0.6.0rc1 This release

9 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