Skip to main content

A cli tool to enforce documentation for code suppressions

Project description

shamefile logo

Tests Lint CodeQL Coverage Quality Gate Docs License Rust

Turn linter suppressions from silent technical debt into reviewable, documented decisions.

shamefile is a CLI that scans your codebase for linter suppressions (# noqa, // eslint-disable, // @ts-ignore, and many more), consolidates them into a single registry, and fails the build until every one of them carries a written justification. Human authors and AI coding agents operate through the same interface.

Why shamefile

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.

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

Documentshame 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 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 — one entry at a time:

$ 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'
  • location and token form the entry's identity.
  • content is the verbatim source line — used for reconciliation when code moves.
  • owner and created_at are populated automatically on first run via git blame.
  • why is the only field you fill in by hand.

Cascade matching

A registry that breaks every time you refactor is worse than no registry. shamefile reconciles entries against source code in two passes:

  1. Location match — exact file:line + token.
  2. Content match — same source line + token (handles line shifts, with rename detection via git).

Renaming a file, reformatting a function, or inserting imports above a suppression all preserve 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

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

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.yaml conflicts on parallel PRs
  • Additional language grammars — Rust, Go, Java, Kotlin, C# via tree-sitter
  • Custom entry fields — attach ticket, reviewer, or deadline metadata to suppressions

Contributing

Missing a token for your linter? Open an issue first — let's agree on scope before you write code.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shamefile-0.1.0rc3.tar.gz (83.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

shamefile-0.1.0rc3-py3-none-win_arm64.whl (1.7 MB view details)

Uploaded Python 3Windows ARM64

shamefile-0.1.0rc3-py3-none-win_amd64.whl (1.8 MB view details)

Uploaded Python 3Windows x86-64

shamefile-0.1.0rc3-py3-none-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

shamefile-0.1.0rc3-py3-none-musllinux_1_2_aarch64.whl (1.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

shamefile-0.1.0rc3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

shamefile-0.1.0rc3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

shamefile-0.1.0rc3-py3-none-macosx_11_0_arm64.whl (1.8 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

shamefile-0.1.0rc3-py3-none-macosx_10_12_x86_64.whl (1.8 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file shamefile-0.1.0rc3.tar.gz.

File metadata

  • Download URL: shamefile-0.1.0rc3.tar.gz
  • Upload date:
  • Size: 83.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for shamefile-0.1.0rc3.tar.gz
Algorithm Hash digest
SHA256 aad796aa95b5f4fa2abc5602d4c9f9bb444b8fe6f929f23b09ae9e758ecd1518
MD5 03540f2186cf84503a7cd68d44aa9708
BLAKE2b-256 07d2728e0f9e17fe6631910e472fefea605aafda669bfd023ac9b0a3c45684d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3.tar.gz:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-win_arm64.whl.

File metadata

  • Download URL: shamefile-0.1.0rc3-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

Hashes for shamefile-0.1.0rc3-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 5a1fa488ba0a8a3a6eb4234aca8cf1db5e86c6e983d9d1616e0927867a5df5be
MD5 58d13ca66f2293467e8b48b427a4e90e
BLAKE2b-256 a71a5cc4c33023e75581358b8cd5624d5c8e209386e11eb9017751252442deb8

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-win_arm64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-win_amd64.whl.

File metadata

  • Download URL: shamefile-0.1.0rc3-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

Hashes for shamefile-0.1.0rc3-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 b1b55fc1a7f05df01ed025d1ad93f922bf453bc1aa335be67d3543bbb3dba9b5
MD5 125f4e682057d3327b85277aa61ac922
BLAKE2b-256 c10d6c319f7441085485107f648db02b820690a4c2a848c6a94e9490eb9ea007

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-win_amd64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc3-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 27b87498d1ab90fd6abb9362ad6852786149e0dce44d8e89958b164fe017233e
MD5 c79000586e9d308ac5fffdc512e4a2ac
BLAKE2b-256 067bbfab8fb8509bb658400ea0f33c5371f731a477e79f72a4d3f8c1371a0b0d

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-musllinux_1_2_x86_64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc3-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 57eb415def137709369a065340f909e18f2492e46c0ca0a7edf15db8f4cf6d1b
MD5 5c50efa95fa7b63dec5340f041063233
BLAKE2b-256 ce57687609452ae93f93a212fd2b470eaabe7818b3d0d26e500aed6556fb44a0

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-musllinux_1_2_aarch64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9c253ac854f1b0d1084b282d142b039b1e20fa9010dbabecdf33fb20499cae83
MD5 13a1411e082dc914d4536dfff8af965c
BLAKE2b-256 7a258c6293c89dc23e0007b68a99891784e14749bd81142f2fbf2b24afd0eecf

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6838f66e607782ac6525c9ed4699dea943e691738ecb44e2492066d4ae186315
MD5 adfc067df58e3d38a81ab76c339b9646
BLAKE2b-256 a81a900b2c6e0bb95727e3efccc8f7dfa5c75b195cbc2a03732a0991b459b686

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc3-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6bfa3298e8b1cdb8defda61a1d33d41beee723e673ce81834e86d1960d146f35
MD5 fc76ff7c931a1f9852ae6611d1b119de
BLAKE2b-256 83ede38c3d007274080bee13adf42b746ebcc4df41ca5e42c1bdc126310e8ac1

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-macosx_11_0_arm64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shamefile-0.1.0rc3-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc3-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4732d642f7a057cbe4ba16ff50121244825c2882adc708772e984006502df4ca
MD5 7afc6d7225bdf2c88d2407ce06f1f7ad
BLAKE2b-256 505a74fc9da0cc94f28f070490dcc3be9876db86518a125b7d5289298ae750d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc3-py3-none-macosx_10_12_x86_64.whl:

Publisher: publish-pypi.yml on BKDDFS/shamefile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page