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.0rc2.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.0rc2-py3-none-win_arm64.whl (1.7 MB view details)

Uploaded Python 3Windows ARM64

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

Uploaded Python 3Windows x86-64

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

Uploaded Python 3musllinux: musl 1.2+ x86-64

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

Uploaded Python 3musllinux: musl 1.2+ ARM64

shamefile-0.1.0rc2-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.0rc2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

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

Uploaded Python 3macOS 11.0+ ARM64

shamefile-0.1.0rc2-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.0rc2.tar.gz.

File metadata

  • Download URL: shamefile-0.1.0rc2.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.0rc2.tar.gz
Algorithm Hash digest
SHA256 5d4bec7c084e1afb05af80ad80bfbe7172bc208f84418410243ccbe5a1982dde
MD5 cd69484d2fa4deb64248202a5aeb1fbe
BLAKE2b-256 339c8aad971a6529c71456041db9ab1af8b2cac8edde5817d7624fbc93844622

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2.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.0rc2-py3-none-win_arm64.whl.

File metadata

  • Download URL: shamefile-0.1.0rc2-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.0rc2-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 59578d9746b1382733aa0a4a4f3798d9265c7eddcbc949e0058c8b0a7510b2b5
MD5 d89d28cf8c92393f300c35fcdeb2d74a
BLAKE2b-256 6735294fee06154c7005847033e82844b05b4f897bf0b62f530e1820e0fc5c39

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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.0rc2-py3-none-win_amd64.whl.

File metadata

  • Download URL: shamefile-0.1.0rc2-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.0rc2-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 431ee1387d4f906c1e876d00d8eace25958a0982acd3cbc2160b9a8ee60e3aab
MD5 b050a107c0fcc74198d04886231ea583
BLAKE2b-256 04b990d12d21d0cd3375c28e54857e9529c3349976d0e11501032809af0dc980

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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.0rc2-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc2-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d7f880467671a0039cdea347cdd132d835520e945a384a3d16bbe262cc4d9612
MD5 2c94d26d7880d6440501383a1fb12636
BLAKE2b-256 7a39183ff2614fdf86c4bd8a217100e10741035fc8ac8a75364a5081c574550c

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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.0rc2-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc2-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 278a9ab9f9d1936431a66f2ac2f4973e2323fb50cb80554c3b5ae8886a269094
MD5 e2fcdc4737b626d9417f853c4f7e4cbf
BLAKE2b-256 d2c48cdafdeb5dfdbb1ca1c3ed73b37a2dcb8de325891d1a2a2264d2f5f8fb7b

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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.0rc2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c7c2b579e55d317db2b085d1089cd8430e7fbac4427d976b9a777f037b1bc526
MD5 fea41cf9ef6f1a067268ce1855207220
BLAKE2b-256 2e5a49f47ef511a6a6f3d24ceeead77b9547ad8b57c13e82b6dcd06fd61f321c

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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.0rc2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 264a3557aaf840476da0b5ee4e11ea45bf7b1c124ab8c6e09652edcaa0b09877
MD5 1fcf502c868eb4448195fe77b14371ff
BLAKE2b-256 f411ee9f4698562052bfbd541dba7c8130c5a49c71e0cc53e8182d25882bb759

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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.0rc2-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 35b23cfda6af4280d6a186a46f1589a67b800911c652800aaa4f9e2a043d5519
MD5 4fc94a6072dffa80465c9b37b1e3d4c9
BLAKE2b-256 cf06320d9ee49391bbbeec1a9d586bdc8dd0e37cfca576ea9766e3b5f10446a3

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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.0rc2-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for shamefile-0.1.0rc2-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 d980bede43c04951549c44641fa9377af32c38f459ff33e879db571df5865460
MD5 b68c0b7177d2dd3f050be7ec6aecf1ee
BLAKE2b-256 726861184ce7ac4827b25332f16777a0c950e14e7d28d83f02090c260cfcd2fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for shamefile-0.1.0rc2-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