AST-based static analysis, in your browser

The bugs your reviewers didn't catch.

codehound hunts subtle correctness and async-safety bugs — the ones that pass code review and only bite in production. Every rule below was distilled from a real bug, found and fixed in a real open-source project. Scan a snippet, a whole GitHub repo, or a local folder further down. Nothing is uploaded: it runs on your machine, in codehound's own Python, compiled to WebAssembly.

100
checks
8
merged / open PRs
~29
frameworks validated on
0
runtime dependencies
Try it now → See the real bugs

Every rule exists because of a bug like this

codehound isn't a demo — these are real defects it found in widely-used open-source projects, each fixed with a regression test verified to fail before the fix and pass after it.

agno 41k★
Merged
CH001 · blocking-call-in-async

The project's original proof point. codehound pointed at agno's own source found requests.get() sitting inside the async Discord on_message handler — freezing the event loop on every attachment, and able to 403 on authenticated URLs. Not a bug anyone was looking for; the scan found it.

agno-agi/agno #8186 →
accelerate 9k★
PR open
CH010 · loop-closure-capture

In distributed-training parameter sync, a list of callbacks — one per model chunk — each captured model_index by reference. Whichever chunk's callback fired last reported the same, wrong index for every chunk. Used across the PyTorch training ecosystem.

huggingface/accelerate #4273 →
optuna 12k★
PR open
CH011 · lru-cache-on-method

Seven node-lookup methods on _FanovaTree were @lru_cache'd directly on the class. Every tree built for a single get_param_importances() call — one per random-forest estimator — stayed reachable through the cache forever, instead of being freed the moment it was done.

optuna/optuna #6859 →
llama_index 40k★
PR open
CH011 · lru-cache-on-method

Same class-level cache mistake, with a compounding twist: VectaraIndex._get_corpus_key's leak meant the class's own __del__ — written specifically to close its HTTP session — never ran. One bug quietly broke a second, unrelated cleanup path nobody had connected to it.

run-llama/llama_index #23089 →
litellm 30k★
PR open
CH011 · lru-cache-on-method

Router._cached_get_model_group_info leaked every Router that ever served a request — and survived even a correctly-called Router.discard(), the class's own documented cleanup method. Proved it independently by testing all four combinations before trusting the fix.

BerriAI/litellm #41582 →
agno 41k★
PR open
CH006 · floating-task

A fire-and-forget asyncio.create_task() in the tracing exporter's async path — the event loop only holds a weak reference to a task, so with nothing else referencing it, traces could be silently dropped mid-run.

agno-agi/agno #8183 →
Read the full findings log →

🔍

Every rejected idea is public too

Most tools only show you what shipped. Eight fully-built checks were corpus-scanned and thrown out this year because the real hits turned out to be correct code, not bugs — the same discipline applied to codehound's own rules that its rules apply to yours.

8
checks rejected
100
checks shipped

Scan a snippet, a repo, or your own code

The exact same 100 checks as the CLI, running in a real CPython build compiled to WebAssembly. Nothing you paste or point it at leaves your machine.

Fetches the repo's Python files over the network (via the GitHub API + raw.githubusercontent.com), then scans them locally. Nothing is sent to any server codehound controls.
paste or edit Python code
Loading Python runtime…
findings
⏳ Fetching Pyodide runtime…

How this actually works

01

Python, compiled to WebAssembly

Pyodide runs a full CPython build in your browser tab. On load, it installs the real, currently-published codehound wheel straight from PyPI with micropip — the exact same package pip install codehound gives you.

02

Your code stays local

A snippet is scanned in memory. A GitHub repo is fetched file-by-file from GitHub's own CDN straight into the browser tab. A local folder never leaves your machine at all — there's no server behind this page to send it to.

03

The same 100 checks as the CLI

This isn't a demo subset — it's codehound.get_checks() and scan_files(), the identical code path codehound scan runs locally. What you see here is what you'd get from the real tool.

04

Every finding is a lead, not a verdict

A finding means the shape looks dangerous, not that it definitely is. Read the message, check the context — some flagged code is genuinely fine, and the findings log above documents real examples of exactly that, checked and cleared.