Skip to main content

Anti-slop linter for AI-assisted codebases

Project description

grain

Anti-slop linter for AI-assisted codebases. Detects AI-generated code and documentation patterns before they land in version control.

What it does

AI code has tells. grain flags them so a human can decide whether to keep, rewrite, or suppress. It does not auto-fix -- fixing requires judgment.

Quick start

pip install grain-lint   # from PyPI
pip install -e .         # from source

Usage

grain check [files...]      # check specific files
grain check --all           # check entire repo
grain install               # install git hooks into .git/hooks/
grain status                # show current config and enabled checks
grain suppress FILE:LINE RULE  # add inline suppression comment

Checks

Python

Rule Severity Description
OBVIOUS_COMMENT error comment restates the following line
NAKED_EXCEPT error broad except clause with no re-raise
RESTATED_DOCSTRING warn docstring just expands the function/class name
VAGUE_TODO error TODO without specific approach or reason
SINGLE_IMPL_ABC warn ABC with exactly one concrete implementation
GENERIC_VARNAME error function named with AI filler (process_data, etc.)
TAG_COMMENT warn untagged comment -- requires # TAG: description format (opt-in)

Markdown

Rule Severity Description
HEDGE_WORD error AI filler words -- see hedge_words in config
THANKS_OPENER error README/CONTRIBUTING opens with "Thanks for contributing"
OBVIOUS_HEADER warn header content fully restated in following paragraph
BULLET_PROSE warn short bullet list that reads better as a sentence
TABLE_OVERKILL warn table with 1 row or constant column

Commit messages

Rule Severity Description
VAGUE_COMMIT error subject too generic (update, fix bug, wip...)
AND_COMMIT error subject contains "and" -- do one thing per commit
NO_CONTEXT error fix/feat with no description of what changed

Config

Create .grain.toml in your repo root:

[grain]
fail_on = ["OBVIOUS_COMMENT", "NAKED_EXCEPT", "HEDGE_WORD", "VAGUE_TODO", "VAGUE_COMMIT"]
warn_only = ["RESTATED_DOCSTRING", "SINGLE_IMPL_ABC", "BULLET_PROSE"]
ignore = []
exclude = ["tests/*", "migrations/*"]

[grain.python]
generic_varnames = ["process_data", "handle_response", "get_result", "do_thing"]
# allowed_comment_tags = ["TODO", "BUG", "FIX", "PERF", "NOTE", "HACK", "FIXME", "XXX", "SAFETY", "REVIEW"]

[grain.markdown]
hedge_words = ["robust", "seamless", "leverage", "cutting-edge", "powerful",
               "you might want to", "consider using", "it's worth noting", "note that"]

Opt-in rules

Some rules are strict enough that they're off by default. Add them to warn_only or fail_on in .grain.toml to activate:

[grain]
warn_only = ["TAG_COMMENT"]

TAG_COMMENT requires every comment to use a structured tag format (# TODO: ..., # NOTE: ..., etc.). Section headers, dividers, shebangs, type: ignore, and noqa are automatically skipped.

Suppression

Add # grain: ignore RULE_NAME to the offending line:

except Exception as e:  # grain: ignore NAKED_EXCEPT
    pass  # intentional -- this is a top-level catch

Or use the CLI:

grain suppress src/main.py:42 NAKED_EXCEPT

pre-commit framework

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/mmartoccia/grain
    rev: v0.1.3
    hooks:
      - id: grain

Output format

path/to/file.py:42  [FAIL] OBVIOUS_COMMENT  "# return result" restates the following line
path/to/README.md:7  [FAIL] HEDGE_WORD  "robust" signals AI-generated prose

Exit 0 = clean. Exit 1 = errors found (pre-commit blocks the commit).

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

grain_lint-0.1.3.tar.gz (22.2 kB view details)

Uploaded Source

Built Distribution

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

grain_lint-0.1.3-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

File details

Details for the file grain_lint-0.1.3.tar.gz.

File metadata

  • Download URL: grain_lint-0.1.3.tar.gz
  • Upload date:
  • Size: 22.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for grain_lint-0.1.3.tar.gz
Algorithm Hash digest
SHA256 5193f541f8ffe4e106011e1ce21131cce8a3c8a603c69d429215cdd15b1c2af5
MD5 857b81d08885dbf018ef7da6a373be5e
BLAKE2b-256 d299eba2391aefb8e324f7a033db42cf28cbab5e9408adae7e99c52c389e5546

See more details on using hashes here.

File details

Details for the file grain_lint-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: grain_lint-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 19.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for grain_lint-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 d8af5256e19b0a0539a1bb0d11d52ece330071d275201ecb16866222a43e3b4f
MD5 20fe9bf7b40e6f6eeeb90ff8a02fc646
BLAKE2b-256 884d8a765ca56f60b5b7fa8ff21fa3b12100d3e09d9557ca8c8dacf1524c37eb

See more details on using hashes here.

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