Inspect, insert, update, remove, and validate project file headers across codebases.
Project description
TopMark
TopMark is a Python command-line tool and library for inspecting, inserting, updating, removing, and validating project file headers across diverse codebases.
It helps keep license, copyright, project, and file metadata consistent through:
- comment-aware header rendering;
- layered configuration and policy controls;
- dry-run-by-default safety;
- stable CI-friendly exit codes;
- machine-readable output formats;
- transparent file-type resolution diagnostics;
- and a public Python API for automation and integration.
Documentation
Full documentation is hosted on Read the Docs:
👉 https://topmark.readthedocs.io/en/latest/
This README provides a compact overview for GitHub and PyPI. Detailed usage, configuration, command-reference, API, CI/CD, and contributor documentation live in the generated documentation site.
Features
- Detect, insert, update, validate, and remove file headers across multiple file types
- Comment-aware rendering for line and block comment styles
- Dry-run by default, with explicit
--applyrequired for mutation - Layered configuration via
topmark.toml,pyproject.toml, user config, explicit config files, and CLI overrides - Policy controls for insertion, update, empty-file behavior, file-type filtering, and content probing
- Resolution diagnostics with
topmark probe - Machine-readable JSON, NDJSON, and Markdown output where supported
- Stable exit-code contracts for CI and scripting
- Public Python API for programmatic access to all CLI commands
- Extensible registry and processor architecture for custom file types and header processors
- Pre-commit, CI, and Git hook friendly
- Preserves standard newline styles, shebangs, BOMs, and file-specific comment rules
- Strictly typed Python implementation using Pyright
Example headers
TopMark adapts headers to the comment syntax of each supported file type.
Bash / Shell
#!/bin/bash
# topmark:header:start
#
# project : TopMark
# file : script.sh
# license : MIT
# copyright : (c) 2025 Olivier Biot
#
# topmark:header:end
echo "Hello, World!"
XML
<?xml version="1.0" encoding="UTF-8"?>
<!--
topmark:header:start
project : TopMark
file : config.xml
license : MIT
copyright : (c) 2025 Olivier Biot
topmark:header:end
-->
<configuration>
<!-- XML content here -->
</configuration>
JavaScript
// topmark:header:start
//
// project : TopMark
// file : app.js
// license : MIT
// copyright : (c) 2025 Olivier Biot
//
// topmark:header:end
console.log("Hello, World!");
CSS
/*
* topmark:header:start
*
* project : TopMark
* file : styles.css
* license : MIT
* copyright : (c) 2025 Olivier Biot
*
* topmark:header:end
*/
body { margin: 0; }
Installation
From PyPI
pip install topmark
TopMark stable releases are published on PyPI.
If you are upgrading from TopMark 0.11.x or earlier, review the migration guide before changing existing configuration, CI jobs, or pre-commit hooks:
From source (development setup)
git clone https://github.com/shutterfreak/topmark.git
cd topmark
make venv
make venv-sync-dev
TopMark uses uv as the canonical dependency manager. pyproject.toml declares dependency
ranges, uv.lock is the committed lock source of truth, and a project-local .venv is used as the
standard environment for editor integration and interactive development.
TopMark's package version is no longer maintained manually in pyproject.toml; installed versions
are derived from Git tags via setuptools-scm.
Run checks to confirm setup:
make verify
make test
Verify CLI
topmark version
topmark --help
For development builds between release tags, topmark version may report SCM-derived development
versions that include commit-based metadata.
Usage
topmark [COMMAND] [OPTIONS] [PATHS]...
Subcommands
| Command | Description |
|---|---|
check |
Add or update TopMark headers |
strip |
Remove TopMark headers |
probe |
Explain file-type and processor resolution |
config check |
Check the merged config for errors. |
config defaults |
Show the built-in default TopMark TOML document |
config dump |
Show resolved configuration (merged TOML), optionally with layered provenance |
config init |
Output the bundled example TopMark TOML resource with documentation |
registry filetypes |
List supported file types from the registry |
registry processors |
List header processors and mappings from the registry |
registry bindings |
List effective filetype to processor bindings |
version |
Print version (PEP 440 or SemVer) |
Examples
# Preview (dry-run)
topmark check src/
# Apply in place
topmark check --apply src/
# Remove headers (dry-run)
topmark strip src/
# Remove headers and apply changes
topmark strip --apply src/
# Treat config warnings as errors for this run
topmark check --strict src/
# Explain how TopMark resolves a file type and processor
topmark probe README.md
# Show candidate scores and match signals
topmark probe -vv README.md
# Filter file types (by local identifier):
topmark check --include-file-types python src/
# Filter file types (by qualified identifier):
topmark check --include-file-types topmark:python src/
# Process one file's content from STDIN
cat README.md | topmark check - --stdin-filename README.md
# Show why a path was filtered by discovery rules
topmark probe __pycache__/example.cpython-312.pyc
# Inspect merged configuration with layered provenance
topmark config dump --show-layers
# Emit machine-readable config provenance + flattened config
topmark config dump --show-layers --output-format json
# Show supported file types in Markdown format
topmark registry filetypes --output-format markdown --long
# List effective filetype to processor bindings
topmark registry bindings --output-format markdown --long
Note:
-v/--verboseapplies only to TEXT output.-q/--quietis available only on commands that support TEXT output suppression, such ascheck,strip,probe,config check, andconfig dump.- Pure informational content-producing commands such as
version,config defaults,config init, and registry commands do not support--quiet.- TopMark does not provide a
--stdinflag. Use the POSIX-style-PATH sentinel together with--stdin-filename NAMEwhen reading one file's content from STDIN.- File-agnostic commands such as
version,config defaults,config init, and registry commands reject positional paths and file-processing STDIN modes.- Markdown output is document-oriented and ignores TEXT-only verbosity controls.
- JSON/NDJSON output is machine-readable and also ignores TEXT-only verbosity controls.
topmark probealso reports explicitly requested paths that were filtered out before resolution, distinguishing between path filters, file-type filters, and a generic fallback.
TopMark preserves standard line endings (LF, CRLF, CR), shebangs, BOMs, and file-specific indentation rules. Non-standard Unicode newline separators (NEL/LS/PS) are treated as ordinary content rather than physical line endings.
Exit codes (CI / scripting)
TopMark uses a small, stable set of exit codes for automation:
SUCCESS (0)- success (no changes needed or changes applied)WOULD_CHANGE (2)- dry-run indicates changes would be made (check,strip)FAILURE (1)- validation failed (config check)USAGE_ERROR (64)- CLI usage error- invalid command/option combinations, positional paths on file-agnostic commands, and unsupported STDIN modes are reported as usage errors
CONFIG_ERROR (78)- configuration error
Other codes (for example UNSUPPORTED_FILE_TYPE (69), PIPELINE_ERROR (70), IO_ERROR (74),
PERMISSION_DENIED (77)) are used for more specific runtime conditions after CLI usage has been
accepted.
For the complete, stable contract, see:
Configuration and Policy
TopMark supports layered configuration discovery and policy-based control over header mutation.
Common configuration sources include:
topmark.tomlpyproject.tomlunder[tool.topmark]- user configuration
- explicit
--configfiles - CLI options
A minimal project configuration looks like this:
[config]
root = true
[fields]
project = "TopMark"
license = "MIT"
copyright = "(c) 2025 Olivier Biot"
[header]
fields = ["file", "file_relpath", "project", "license", "copyright"]
relative_to = "."
[policy]
header_mutation_mode = "all"
allow_header_in_empty_files = false
empty_insert_mode = "logical_empty"
render_empty_header_when_no_fields = false
allow_reflow = false
allow_content_probe = true
[policy_by_type."topmark:python"]
allow_header_in_empty_files = true
[files]
include_file_types = ["topmark:python", "topmark:markdown", "topmark:env"]
exclude_file_types = ["topmark:html"]
exclude_from = [".gitignore"]
TopMark can also control mutation policy, empty-file behavior, content probing, and per-file-type
overrides. File type filters and policy_by_type keys accept local identifiers such as python
when unambiguous and qualified identifiers such as topmark:python when explicitness matters.
Use the CLI to inspect the effective configuration:
topmark config dump --show-layers
topmark config dump --show-layers --output-format json
Detailed configuration and policy behavior is documented in:
- Configuration Guide (hosted docs)
- Example TOML document
- Policy Guide (hosted docs)
- Filtering (hosted docs)
Pre-commit Integration
TopMark includes pre-commit hooks for automated header management.
| Hook ID | Purpose |
|---|---|
topmark-check |
Validate headers (non-destructive) |
topmark-apply |
Apply header updates (manual) |
Install hooks:
pre-commit install
pre-commit run --all-files
Manual header fix (safe interactive mode):
pre-commit run topmark-apply --hook-stage manual --all-files
Public API
TopMark exposes a public Python API for programmatic checks, stripping, probing, and registry discovery.
Public API callers should use the functions and DTOs exposed from topmark.api. Runtime helpers,
resolver internals, and pipeline contexts are implementation details.
Example dry-run check:
from pathlib import Path
from topmark import api
paths: list[Path] = [Path("src")]
policy = {
"header_mutation_mode": "add_only",
}
# Dry-run (apply=False) header checks
result = api.check(
paths,
apply=False,
policy=policy,
report="actionable",
)
print(result.summary)
print(result.had_errors)
# Apply changes
result = api.check(
paths,
apply=True,
)
# Remove headers
result = api.strip(
paths,
apply=True,
)
For read-only resolution diagnostics, use api.probe(), which returns stable public DTOs without
exposing resolver internals or pipeline objects.
from pathlib import Path
from topmark import api
# Explain file-type / processor resolution
probe_result = api.probe([Path("README.md")])
for file_result in probe_result.files:
print(file_result.path, file_result.status, file_result.reason)
For API details, see:
Packaging and Versioning
TopMark uses Git-tag-driven package versions via setuptools-scm. Versions are derived from Git
tags at build time rather than maintained manually in pyproject.toml.
TopMark follows Semantic Versioning for compatibility intent while Python packaging uses SCM-derived PEP 440 versions.
Typical stable-release tag forms are:
- final releases:
vX.Y.Z
Typical pre-release tag forms are:
- alpha releases:
vX.Y.ZaN - beta releases:
vX.Y.ZbN - release candidates:
vX.Y.ZrcN
Build and validate artifacts locally:
make package-check
Releases are published by GitHub Actions when matching Git tags are pushed.
- prereleases are published to TestPyPI for validation;
- stable releases are published to PyPI.
For detailed release architecture and maintainer guidance, see:
Development
For day-to-day development, use the local .venv for editor integration and interactive work.
Automated testing, typing, documentation, and validation still run in isolated environments managed
by nox, which keeps local convenience separate from reproducible QA automation.
Typical development workflows:
To run the full QA suite across all supported Python versions:
make test # nox -s qa (matrix)
make api-snapshot # nox -s api_snapshot (matrix)
Run QA for a single Python version:
nox -s qa -p 3.13
nox -s qa_api -p 3.13
For faster iteration:
make pytest # run tests in current interpreter (no nox)
make format # formatting
make lint # static linting
make docs-build # build the docs
make verify # formatting, linting, docs, links
For contributor setup and validation details, see:
- Contributing (hosted docs)
- CI/CD and validation documentation (hosted docs)
- Documentation conventions (hosted docs)
License
MIT License © 2025 Olivier Biot
See LICENSE
TopMark - consistent headers for consistent projects.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file topmark-1.0.0.tar.gz.
File metadata
- Download URL: topmark-1.0.0.tar.gz
- Upload date:
- Size: 1.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68f8e4414b751edbf85cb913f95b2ff6a3cd9217f96385cc5267665dedc3d60f
|
|
| MD5 |
d6a282d7125fc4953825e79230580ecd
|
|
| BLAKE2b-256 |
7f015f88a38d24e4250ffb7e1372d0df52c151dd81c91ee6aadad259a34387e7
|
Provenance
The following attestation bundles were made for topmark-1.0.0.tar.gz:
Publisher:
release.yml on shutterfreak/topmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
topmark-1.0.0.tar.gz -
Subject digest:
68f8e4414b751edbf85cb913f95b2ff6a3cd9217f96385cc5267665dedc3d60f - Sigstore transparency entry: 1595180900
- Sigstore integration time:
-
Permalink:
shutterfreak/topmark@a8031687715818a704115ebadf8f8011036d60c1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/shutterfreak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a8031687715818a704115ebadf8f8011036d60c1 -
Trigger Event:
workflow_run
-
Statement type:
File details
Details for the file topmark-1.0.0-py3-none-any.whl.
File metadata
- Download URL: topmark-1.0.0-py3-none-any.whl
- Upload date:
- Size: 569.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d210efb6f6f22a04d0376c58e2ee4ccbfbe96ac23f46b043e5341b731e087ff2
|
|
| MD5 |
091dd452034bb1741f4acc65c0ec38ab
|
|
| BLAKE2b-256 |
856e7840be9d66f176715e8dcb8e95d23f1c6bcc1c1062feb4e7b179ab138ac8
|
Provenance
The following attestation bundles were made for topmark-1.0.0-py3-none-any.whl:
Publisher:
release.yml on shutterfreak/topmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
topmark-1.0.0-py3-none-any.whl -
Subject digest:
d210efb6f6f22a04d0376c58e2ee4ccbfbe96ac23f46b043e5341b731e087ff2 - Sigstore transparency entry: 1595180974
- Sigstore integration time:
-
Permalink:
shutterfreak/topmark@a8031687715818a704115ebadf8f8011036d60c1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/shutterfreak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a8031687715818a704115ebadf8f8011036d60c1 -
Trigger Event:
workflow_run
-
Statement type: