A cli tool to enforce documentation for code suppressions
Project description
Turn silent tech debt into reviewable and documented decisions.
shamefile won't let anyone silence a linter warning in your code without writing down why.
People are lazy. Both committer and code reviewer.
- The committer slaps a
// NOLINTcomment when there's no easy fix. They don't justify it — in most languages there's no good place for that. - The code reviewer focuses on more important things: security, bugs, design. There's no dedicated time for checking new suppression arrivals.
Shamefile adds shamefile.yaml for the code reviewer and the shame CLI for the committer to give them tools to react before tech debt gets out of control.
Why it's important
A mysterious # noqa with no explanation, left by a developer who moved on years ago. Nobody remembers why. Nobody wants to touch it. This is how legacy code accumulates — silently, one linter suppression at a time.
shamefile interrupts that pattern. Every suppression is tracked in a single shamefile.yaml — one file, one purpose. When it changes in a pull request, a reviewer sees the full cost of a shortcut in a single diff. And as AI coding agents become routine PR authors, the registry acts as a consistent gate: whether a suppression was introduced by a human or a model, it ships with a written justification or it doesn't ship at all.
How it works
shamefile exposes two stages, one command each.
Scan — shame me . walks your project, finds every suppression token, and syncs the central shamefile.yaml. New suppressions are registered with auto-filled metadata (owner from git blame, timestamp, source line). Stale entries are removed. The command fails if any entry lacks a why.
Document — shame next shows the first undocumented suppression, with the exact source line highlighted. Provide the reason inline (shame next "<reason>"), or target a specific entry with shame fix <location> <token> --why "<reason>".
The same interface works for a developer opening a PR and for an AI agent iterating through gaps one at a time — without having to read the full registry into context.
Workflow
1. Developer writes code with a suppression:
result = parse_legacy_api(raw) # type: ignore
2. Pre-commit (or manual) run surfaces the gap:
$ shame me .
Scanning . for suppressions...
Added 1 new entries to /home/user/myproject/shamefile.yaml
1 suppressions need documentation (why).
Run `shame next` to see the first one, or `shame next "<reason>"` to fill its why.
...
3. Developer documents it:
$ shame next
./src/api.py:42
|
42| result = parse_legacy_api(raw) # type: ignore
Fix with:
shame next "<reason>"
shame fix "./src/api.py:42" "# type: ignore" --why "<reason>"
$ shame next "legacy API returns untyped dict; types module in progress"
Documented: # type: ignore at ./src/api.py:42
All entries documented. No shame today!
4. Developer commits both api.py and shamefile.yaml. The shortcut and its justification land in the same PR, reviewable in a single diff.
CI/CD integration
On the CI side, shame me . --dry-run is read-only and deterministic. It validates three contracts:
| Check | Meaning |
|---|---|
| Coverage | Every suppression in code is registered in shamefile.yaml |
| Staleness | Every registered entry still points at a live suppression in code |
| Justification | Every entry has a non-empty why |
A failure on any of the three exits non-zero.
# .github/workflows/ci.yml
- name: Check suppressions
run: shame me . --dry-run
| Flag | Description |
|---|---|
--dry-run (-n) |
Read-only validation for CI/CD — never writes to disk |
--hidden |
Also scan hidden files and directories (dotfiles) |
Registry format
shamefile.yaml lives at the project root (git root if available, otherwise the working directory). Every entry is human-readable and stable under git diff:
---
config: {}
entries:
- location: ./src/api.py:42
token: '# type: ignore'
content: 'result = parse_legacy_api(raw) # type: ignore'
created_at: 2026-04-17T21:15:05Z
owner: Anna Nowak <anna@example.com>
why: 'legacy API returns untyped dict; types module in progress'
locationandtokenform the entry's identity.contentis the verbatim source line — used for reconciliation when code moves.ownerandcreated_atare populated automatically on first run viagit blame.whyis the only field that requires a written justification — from a developer or an AI agent. The PR reviewer decides whether the reason is good enough.
Cascade matching
A registry that breaks every time you refactor is worse than no registry. shamefile reconciles entries against source code in two passes:
- Location match — exact
file:line+ token. - Content match — same source line + token (handles line shifts, with rename detection limited to the most recent commit via
git diff HEAD~1..HEAD -M).
Reformatting a function or inserting imports above a suppression preserves the entry — owner, created_at, and why stay intact. Entries are only removed when the token itself is gone from the code.
Supported tokens
| Token | Tool | Language |
|---|---|---|
# noqa |
Flake8 / Ruff | Python |
# pylint: disable |
Pylint | Python |
# type: ignore |
Mypy | Python |
# pyright: ignore |
Pyright | Python |
# pytype: disable |
Pytype | Python |
# pyre-ignore / # pyre-fixme |
Pyre | Python |
nosec |
Bandit | Python |
# pragma: no cover |
Coverage.py | Python |
# fmt: off / # fmt: skip |
Black / Ruff | Python |
# isort: skip |
isort | Python |
# lint-fixme / # lint-ignore |
Fixit | Python |
# autopep8: off |
autopep8 | Python |
// eslint-disable, /* eslint-disable |
ESLint | JS / TS / TSX |
// tslint:disable, /* tslint:disable |
TSLint | TS / TSX |
// @ts-ignore, /* @ts-ignore |
TypeScript | JS / TS / TSX |
// @ts-expect-error, /* @ts-expect-error |
TypeScript | JS / TS / TSX |
Experimental tokens
New languages added via the Add a language template land here first. They have passed the existing test suite and a sanity run on a real codebase, but no real-world showcase has been contributed yet. Promotion to Supported tokens happens through the Verify and release a language flow.
| Language |
|---|
Supported file extensions: .py, .js, .jsx, .mjs, .cjs, .ts, .tsx.
Installation
| Source | Command |
|---|---|
| npm | npm install -g shamefile |
| PyPI | pip install shamefile |
| crates.io | cargo install shamefile |
| From source | cargo install --git https://github.com/BKDDFS/shamefile |
| Homebrew | coming soon |
All channels install the shame CLI. Run shame --help to verify.
Or as a pre-commit hook:
# .pre-commit-config.yaml
- repo: https://github.com/BKDDFS/shamefile
rev: main
hooks:
- id: shamefile
Roadmap
- MCP server — native integration for LLM-based PR authors (avoids loading the full registry into agent context)
- Custom git merge driver — auto-resolve
shamefile.yamlconflicts on parallel PRs - Additional language grammars — Rust, Go, Java, Kotlin, C# via tree-sitter
- Custom entry fields — attach
ticket,reviewer, ordeadlinemetadata to suppressions
Contributing
Contributions are welcome. Where you start depends on what you have:
- Found a bug? Open an issue with a minimal repro.
- Idea or design question? Open a Discussion under Ideas so direction can be agreed before any code is written.
- Usage question or trouble setting things up? Ask in Q&A.
- Want to send a PR? Read CONTRIBUTING.md first — dev setup, build/test/lint commands, commit format.
- Security vulnerability? Use the private advisory form — see SECURITY.md. Do not open a public issue.
By participating you agree to the Code of Conduct.
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 Distributions
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 shamefile-0.1.2.tar.gz.
File metadata
- Download URL: shamefile-0.1.2.tar.gz
- Upload date:
- Size: 137.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
151a80c29d33398e83e49969a9b495e95161f24a34af0aa2a63a86e41d992b74
|
|
| MD5 |
63fb8bddbb19fc469505c0e38c0cf6b0
|
|
| BLAKE2b-256 |
aa1be2cbc3a5ea5af1fda7b4009b144ef83d62c0221031a86162caacd99befc8
|
Provenance
The following attestation bundles were made for shamefile-0.1.2.tar.gz:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2.tar.gz -
Subject digest:
151a80c29d33398e83e49969a9b495e95161f24a34af0aa2a63a86e41d992b74 - Sigstore transparency entry: 1438177018
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-win_arm64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-win_arm64.whl
- Upload date:
- Size: 1.7 MB
- Tags: Python 3, Windows ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af08a7588e8f57d8a56eb9505f98de100d4713e8abc06a063a8dbcd2c6b12bed
|
|
| MD5 |
0d9be3f322e767d3c98be903f03795bd
|
|
| BLAKE2b-256 |
33014b84250a272610a7e6c302d736d0e534f241b4896c2b765845f0aea5a523
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-win_arm64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-win_arm64.whl -
Subject digest:
af08a7588e8f57d8a56eb9505f98de100d4713e8abc06a063a8dbcd2c6b12bed - Sigstore transparency entry: 1438177060
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-win_amd64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-win_amd64.whl
- Upload date:
- Size: 1.8 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1f3e96157d5eddfee54c96f94bd5abb714376b596f8153a5230568713e7deec
|
|
| MD5 |
ce651129aa38d638e49790c5558c24ea
|
|
| BLAKE2b-256 |
c40f0653202001984190a861eb795b006fd40f4f6b4ec815b82134d11b5f16e9
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-win_amd64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-win_amd64.whl -
Subject digest:
b1f3e96157d5eddfee54c96f94bd5abb714376b596f8153a5230568713e7deec - Sigstore transparency entry: 1438177075
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.0 MB
- Tags: Python 3, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0453070d51199c2b3d083ea09c8932d78cc70132476ec7e1ffea9a9795b4a947
|
|
| MD5 |
1601a62222224193a2b3f586e22784e6
|
|
| BLAKE2b-256 |
a7d6599f071d20e1c1c0089acfde27c49730d091c352ec13186713c074bb1210
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-musllinux_1_2_x86_64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-musllinux_1_2_x86_64.whl -
Subject digest:
0453070d51199c2b3d083ea09c8932d78cc70132476ec7e1ffea9a9795b4a947 - Sigstore transparency entry: 1438177128
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 1.8 MB
- Tags: Python 3, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e5a19366684a233b1bfb7e4f43735b6bdeebb0ea903f53d78ceca7133bf5a4c
|
|
| MD5 |
390b615c246de4889e1ba05f8678e9c3
|
|
| BLAKE2b-256 |
99ec2db020e485cfddd59e3b7f97a051e121fce650d3a460163245c47f263f7a
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-musllinux_1_2_aarch64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-musllinux_1_2_aarch64.whl -
Subject digest:
8e5a19366684a233b1bfb7e4f43735b6bdeebb0ea903f53d78ceca7133bf5a4c - Sigstore transparency entry: 1438177049
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.9 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53ff1cb0feeb2e426d376273e15799a4580690dffcdb4a0c5d98c012c754acd9
|
|
| MD5 |
ea1ba00670e99bbdf595ecad7b1a6df2
|
|
| BLAKE2b-256 |
c10af7923689d71090e02e692583866c085fb6d99528ff939a8fea8574e8c40d
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
53ff1cb0feeb2e426d376273e15799a4580690dffcdb4a0c5d98c012c754acd9 - Sigstore transparency entry: 1438177024
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.8 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6b6d605698ca035537ebbc429614f646b3c086c126dc522526020f3e63df6b4
|
|
| MD5 |
5f0f3c3f22b70fde0220bea1a7729ff2
|
|
| BLAKE2b-256 |
ebcae7f5abc7bd3a6a782fff313eb79b1fac093d9a17705c4befedf3a3ac01e7
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
e6b6d605698ca035537ebbc429614f646b3c086c126dc522526020f3e63df6b4 - Sigstore transparency entry: 1438177083
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.8 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f22b986e127bfd90013a230b2d5a1fd1f113310c9dc98b540c716a3b3d81982b
|
|
| MD5 |
32772f00e6d3ed2ac8176c81a11228d3
|
|
| BLAKE2b-256 |
7fe2e5ee18a45a91e1f9d13e03e76458bc206ff0c9fee223ad07dea6833b7695
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-macosx_11_0_arm64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-macosx_11_0_arm64.whl -
Subject digest:
f22b986e127bfd90013a230b2d5a1fd1f113310c9dc98b540c716a3b3d81982b - Sigstore transparency entry: 1438177097
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file shamefile-0.1.2-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: shamefile-0.1.2-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38782d806a115534e5df8c754a207d0c06f8edd8fa2e40553bfd30e2df16f463
|
|
| MD5 |
4ed2e3d1628a30821c33d23126d292dc
|
|
| BLAKE2b-256 |
8bceedf5774ec2c288c2aed24e59c4c03f4d0c0511c8e313062b64e6680fb8ab
|
Provenance
The following attestation bundles were made for shamefile-0.1.2-py3-none-macosx_10_12_x86_64.whl:
Publisher:
publish-pypi.yml on BKDDFS/shamefile
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shamefile-0.1.2-py3-none-macosx_10_12_x86_64.whl -
Subject digest:
38782d806a115534e5df8c754a207d0c06f8edd8fa2e40553bfd30e2df16f463 - Sigstore transparency entry: 1438177116
- Sigstore integration time:
-
Permalink:
BKDDFS/shamefile@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/BKDDFS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3c7442e4b32260d44a34558e45d27563b05da8e9 -
Trigger Event:
release
-
Statement type: