Skip to content

Configuration

One explicit policy for your source files. Choose the languages, paths, and notice that belong to your project.

Configuration files

Discovery searches upward from the invocation directory and selects the nearest applicable policy. Within each directory, priority is:

Priority File Policy location
1 .lmh.toml Top-level keys.
2 pyproject.toml [tool.lint-my-headers].
3 Cargo.toml [package.metadata.lint-my-headers] or [workspace.metadata.lint-my-headers]. Package settings take precedence.
4 package.json A "lint-my-headers" object.

Manifests without LMH settings are skipped. Invalid configurations fail; configurations are never merged. To select an exact file:

lmh check --config Cargo.toml

Other explicit TOML filenames use the [tool.lint-my-headers] section. Configured paths are relative to the policy file. Positional CLI paths are relative to the invocation directory. CLI policy options override file settings.

Rust example

[package.metadata.lint-my-headers]
owner = "Example Organization"
starting-year = 2024
license = "Apache-2.0"
languages = ["rust"]
paths = ["src", "tests"]
ignore-folders = ["target"]

For a virtual workspace, use [workspace.metadata.lint-my-headers]. Go modules, SwiftPM/Xcode projects, and shell or C/C++ projects can use .lmh.toml; go.mod, go.work, and Package.swift do not supply header policy.

Options

Key / CLI option Meaning and default
owner / --owner Required exact, single-line copyright owner.
starting-year / --starting-year Required earliest accepted file creation year.
creation-year / --creation-year Unreleased source only. Optional declared first year for inserting missing headers; default unset. Applies to all selected missing headers, not existing ones.
license / --license SPDX identifier selecting a prose notice; requires a local LICENSE.
license-notice / --license-notice Custom notice file; configure exactly one license source.
paths / positional paths Selected files or directories; default ..
languages / --languages Non-empty language allowlist; default ["python"].
ignore-files / --ignore-files Exact excluded basenames; default ["__init__.py"].
ignore-folders / --ignore-folders Excluded subtrees; default [".github"].

Select files with the same actual creation year when inserting headers. Run separately for each year; one shared creation-year does not describe mixed-age files.

Configuration lists are arrays. CLI language and ignore lists are comma-separated and replace the corresponding configured list:

lmh check --languages typescript,rust --ignore-folders node_modules,target

Exclusions apply to explicit inputs too. Limit paths or exclude dependency/build directories such as node_modules, target, vendor, and .build; excluded subtrees are not traversed. The tool does not infer exclusions from .gitignore.

Supported languages

Only enabled, supported extensions are checked, including for explicit files. Unknown language names and empty language lists fail.

Selector Extensions Header marker
python .py #
javascript .js, .jsx, .mjs, .cjs //
typescript .ts, .tsx, .mts, .cts, including declarations //
rust .rs //
go .go, including test and platform files //
swift .swift, including Package.swift //
bash (alias shell) .sh, .bash #
c .c, .h //
cpp (alias c++) .cc, .cpp, .cxx, .c++, .C, .hh, .hpp, .hxx, .h++, .H, .ipp, .tpp, .inl, .h //

Shared .h headers are checked with either C selector, using C first and falling back to C++ when needed. Other extensions and extensionless shebang scripts are skipped. Files are checked regardless of build tags or platform suffixes.

Header layouts

Use the example header with the appropriate comment marker and blank lines. A custom license-notice file can contain plain text; existing Python-commented notice files remain accepted. Custom notices must contain non-whitespace text after removing Python comment markers. Blank notices fail with exit 2 before source files are checked or repaired. Notice lines must match in full, including the final line when the notice file has no trailing newline.

Additional layouts (unreleased)

These layouts require the source checkout. Published 0.7.0 uses the prose layout above. Existing-header repairs still change only the end year.

Layout Rules
Prose Copyright, Copyright (C), or Copyright (c), followed by a four-digit year/range and the exact owner. Comma and final period are optional. Keep one blank or marker-only line before the matching notice.
Ordinary block Languages using // also accept the whole header inside /* ... */. Leading * markers are optional; the closing delimiter may follow the final notice.
SPDX pair One SPDX-FileCopyrightText and one SPDX-License-Identifier, in either order with optional blank lines. Owner and configured identifier must match exactly. Keep the local LICENSE.

For example, with owner = "Example Organization" and license = "Apache-2.0":

/*
 * SPDX-FileCopyrightText: 2024-2026 Example Organization
 * SPDX-License-Identifier: Apache-2.0
 */

The pair also works in line comments: # for Python/Bash, // for other languages. A prose copyright with an SPDX identifier is accepted, as is a full prose notice followed by a matching identifier. Custom notices must match in full, including text after any SPDX tag; compound expressions are not evaluated.

SPDX-only blocks contain only the pair and blank lines. Separate later line-comment notes with a blank line. Conflicting legal text anywhere in the leading comments, duplicate fields, nested legal blocks, and documentation comment headers refuse repair. Multiple holders, omitted years, sidecars, and REUSE.toml are unsupported. LMH checks declared policy, not legal compliance.

Python

UTF-8 BOM, shebang, and PEP 263 cookie are preserved. Verified encodings: UTF-8, ASCII, Latin-1, and Windows-1252. Other codecs fail without repair.

JavaScript / TypeScript

UTF-8 BOM, shebang, CRLF, and body are preserved. A shebang needs a blank separator before the header. Bare CR headers and Unicode line separators are refused.

Rust

UTF-8 BOM, shebang, and newline style are preserved. Use ordinary // headers; crate attributes follow the header. Shebangs need a blank separator; ambiguous comment-prefixed #! forms are refused.

Go

UTF-8 BOM and CRLF are preserved. Leading //go:build and // +build directives need a blank separator; constraints after the header are also accepted.

Swift

UTF-8 BOM, CRLF, and shebang are preserved. A leading // swift-tools-version: stays first, with a blank separator before the header.

Bash / shell

UTF-8 BOM, CRLF, shebang, and executable permissions are preserved. A shebang needs a blank separator; other shell dialects are skipped.

C / C++

UTF-8 BOM, CRLF, and body are preserved. Put include guards and #pragma once after the header.

Validation stops at the first code line after allowed preambles and leading comments/blank lines. Later copyright notices and body syntax errors are ignored; the entire file must still decode successfully. Duplicate notices and copyright-bearing documentation comments in the leading region refuse repair. Published 0.7.0 also refuses copyright-bearing ordinary blocks; the unreleased layouts above support unambiguous ordinary blocks. Directory discovery skips symlinks and reparse points. Explicit linked files may be checked, but repairs refuse linked files/parents, multiple hard links, and concurrently changed targets.

The bundled SPDX snapshot is v3.28.0, retaining previously accepted v3.17 names/URLs, including KiCad-libraries-exception. Compound SPDX expressions and new exception semantics are unsupported. Selecting a notice does not establish legal or SPDX compliance.