Skip to main content

Find the mistakes AI leaves behind in your code. Like tests, but for AI slop.

Project description

vibelint

Find the mistakes AI leaves behind in your code.

Your ai assistant writes code that imports cleanly, reads well, and looks finished. Some of it does nothing. vibelint runs over a Python project like a test suite and reports every place the model invented an API, left a function unwritten, swallowed an error, or produced a test that cannot fail.

vibelint finding 25 problems in an AI-written project

In full (not --quiet) it shows the offending line and what to do about it:

$ vibelint examples/vibe_coded_app

  app.py
      3  x  GHOST IMPORT      `fastjson` does not exist: not in the standard library, not
                              installed, not part of this project, and not in your dependencies
         |  import fastjson
         -> Check the real package name before installing anything with this name -
            attackers register hallucinated package names on PyPI.

     13  x  GHOST FUNCTION    `sanitize_input()` is not defined anywhere in this project
         |  clean_order = sanitize_input(order)

     27  x  LOST AWAIT        send_email() is async, but it is called without `await`,
                              so its body never runs
         |  services.send_email(
         -> Write `await send_email(...)`.

  tests/test_orders.py
     14  x  TEST THEATER      test_truncate_long_text() runs code but never asserts anything,
                              so it can only fail if the code crashes
     21  x  FAKE ASSERT       `assert 1 == 1` is true no matter what the code does

  ────────────────────────────────────────────────────────────
  25 flops  ·  15 critical  ·  10 warning  ·  5 of 5 files affected
  checked in 0.18s

Why this is not just another linter

Existing linters check style and syntax — things a human gets wrong. Generated code fails differently. It is syntactically perfect and semantically hollow.

Nothing else catches these, because until recently nothing wrote them at scale:

  • A test that sets up an elaborate scenario and then asserts nothing.
  • A function with a thorough docstring describing behaviour it does not have.
  • client.send_json() — a method name so plausible you never think to check it exists.
  • # In a real implementation, you would validate the token here — shipped to production.

Install

pip install vibelint

Zero dependencies. Python 3.9+. Windows, macOS and Linux. It never runs, imports, or evaluates the code it analyses — everything is read from the syntax tree.

If pip or vibelint isn't found

macOS / Linux — the system Python has no pip command, only the module, and installed scripts land somewhere not on PATH:

python3 -m pip install --user vibelint
python3 -m vibelint .                     # always works

To type vibelint directly, add the script directory to your shell:

echo 'export PATH="$HOME/Library/Python/3.9/bin:$PATH"' >> ~/.zshrc   # macOS

Windows — use the launcher if pip isn't on PATH:

py -m pip install vibelint
py -m vibelint .

python -m vibelint is equivalent to the vibelint command everywhere, so it is the reliable form when PATH is uncooperative.

Use

vibelint                   # check the current directory
vibelint src/              # check one directory
vibelint app.py            # check a single file

vibelint --only VC040      # only test-theater findings
vibelint --ignore VC030    # hide a rule you disagree with
vibelint --json            # machine-readable, for CI
vibelint --list            # describe every check

Silence a single line:

result = risky()  # vibelint: ignore
result = risky()  # noqa: VC030

Exit codes: 0 clean, 1 findings at or above --fail-on (default warning), 2 usage error.

What it catches

Code Check What it means
VC001 GHOST IMPORT Package does not exist anywhere — not stdlib, not installed, not declared, not local
VC002 GHOST FUNCTION A call to a function that was never written
VC003 GHOST METHOD A method that does not exist on the module it is called on
VC010 PLACEHOLDER A function with a docstring and no implementation
VC011 MODEL CONFESSION A comment where the model admits the code is not real
VC020 FAKE VALUE Placeholder credentials wired into live code
VC021 FAKE ENDPOINT example.com used as a real service
VC022 FAKE FALLBACK os.getenv("KEY", "your-key-here") — fails silently in production
VC030 SILENT FAIL Errors caught and discarded
VC031 SWALLOWED RETURN return inside finally, which throws away the exception
VC040 TEST THEATER A test that asserts nothing and cannot fail
VC041 FAKE ASSERT assert True — true regardless of the code
VC042 MOCK TAUTOLOGY A test that only asserts on values it mocked itself
VC050 LOST AWAIT An async function called without await, so it never runs
VC051 BLOCKING ASYNC time.sleep() inside async def, freezing the event loop

It stays quiet on good code

A linter that cries wolf gets uninstalled. Every rule is calibrated against real, mature, human-written code rather than tuned only to catch things.

Across 241 files of pip and setuptools source, vibelint reports 2 critical findings. Nearly all of the remaining output is VC030 — real error-swallowing that is genuinely there.

Getting to that number meant teaching the checks about how Python is actually written:

  • raise NotImplementedError in a base class is informal abstract, not an unfinished job.
  • except KeyboardInterrupt: with a real handler body is correct; only discarding it is a bug.
  • try: import tomllib / except ImportError: import tomli is a compatibility shim, not a hallucination.
  • A package in requirements.txt but not installed is your setup, not the model's invention.
  • Vendored directories are somebody else's code and are skipped.

Speed

The whole Python standard library - 680 files, 306,000 lines - takes about 27 seconds on a laptop, or roughly 11,000 lines a second. A normal project is a fraction of that: a few thousand lines finishes before you lift your hand off the keyboard.

Each file is parsed once and its nodes bucketed by type, so adding a sixteenth check costs almost nothing - the tree is already walked.

In CI

- name: vibelint
  run: |
    pip install vibelint
    vibelint . --fail-on critical

How it works

  1. Index — parse every file and record what the project genuinely defines: functions, classes, methods, class hierarchies, async definitions.
  2. Check — walk each file once, bucket the nodes by type, and run all fifteen rules against that shared view.
  3. Report — group findings by file, ranked by severity, each with the offending line and a concrete fix.

The index is what makes ghost detection possible: no single file can tell you whether helpers.format_date() is real, but the whole project can.

Roadmap

  • JavaScript / TypeScript. The flops are identical in every language — only the parser is Python-specific, and the checks are deliberately separated from parsing.
  • Editor integration, so findings appear as you accept a suggestion rather than afterwards.
  • Config file for per-project severity overrides.

Contributing

A new rule is one Check subclass and one line in the registry. The bar for merging: it must fire on generated code and stay silent on pip and setuptools.

git clone <repo> && cd vibelint
pip install -e ".[dev]"
python -m pytest tests/ -q
vibelint examples/vibe_coded_app     # should report 25 flops

The README demo and the social card are both generated from the tool's real output, so they cannot drift from what it actually prints:

python3 tools/make_demo.py      # -> demo.svg
python3 tools/make_social.py    # -> social-preview.png  (macOS)

License

MIT

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

vibelint-0.3.1.tar.gz (63.8 kB view details)

Uploaded Source

Built Distribution

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

vibelint-0.3.1-py3-none-any.whl (55.0 kB view details)

Uploaded Python 3

File details

Details for the file vibelint-0.3.1.tar.gz.

File metadata

  • Download URL: vibelint-0.3.1.tar.gz
  • Upload date:
  • Size: 63.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for vibelint-0.3.1.tar.gz
Algorithm Hash digest
SHA256 d3318471236d721886b052e5b887a982f9750a765df23bd278fb9d0a1c0444c7
MD5 41f007e94940d8e2616b712f88ad66e3
BLAKE2b-256 a1e40c92d5fca7aa2b5142d1550caba9442d5bcc3459133c9669d061748304ad

See more details on using hashes here.

File details

Details for the file vibelint-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: vibelint-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 55.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for vibelint-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e056e47432d40e8a8cf887a96f16d39c1a2f54bd51f41223b14e31bae22e1a10
MD5 9871b39e0a78e39c973c7504d82d4bc5
BLAKE2b-256 c2c4f4a58788879c1db56e3157a65e727cfbf09c4ed799e0a82bf880bf20cdbf

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