Your agent writes bad Python. This catches it.
Project description
Your agent writes bad Python. This catches it.
A static analyzer for AI-generated Python code. Catches 25 patterns Claude Code, Cursor, Copilot, Codex, Gemini, and friends produce: bare except, hardcoded secrets, async/sync mismatch, dead defenses, fake type hints, stub comments shipped as production code. Then installs a skill into your agent so it stops writing them.
Install · CLI · Rules · Leaderboard · vs alternatives
Install
Install differs by harness. If you use more than one, install aidoctor separately for each.
Claude Code
Register the marketplace and install the plugin:
/plugin marketplace add ankit-aglawe/aidoctor
/plugin install aidoctor@ankit-aglawe
After install, just talk to Claude in plain English. Three skills auto-load:
- scan — runs aidoctor, summarizes the top findings, asks before fixing
- simplify — three-angle review (reuse / quality / efficiency), then fixes
- python-rules — auto-loads when you write Python; your agent reads the 25 rules first
Slash forms /aidoctor:scan and /aidoctor:simplify work too.
Cursor
In Cursor Agent chat:
/add-plugin aidoctor
Or run uvx aidoctor install once — it writes ~/.cursor/rules/aidoctor.mdc.
Codex CLI
Drop the rules file into Codex's config dir:
uvx aidoctor install
Writes ~/.codex/skills/aidoctor.md. Codex reads it automatically when generating Python.
Gemini CLI
uvx aidoctor install
Writes ~/.gemini/skills/aidoctor.md.
OpenCode
uvx aidoctor install
Writes ~/.config/opencode/rules/aidoctor.md.
Any other agent (Aider, Copilot, custom)
uvx aidoctor skill --format generic > my-agent/rules/aidoctor.md
Or paste this prompt into the agent:
Install aidoctor and run my first scan.
- Run
uvx aidoctor install(orpip install aidoctor && aidoctor installifuvxis missing).- Run
uvx aidoctor scan .in the current project.- Summarize in one paragraph: (a) the score out of 100 and its label, (b) the top 3 rule violations and what each means in plain English, (c) whether to fix errors or warnings first.
- Do not modify any files. Stop after the summary.
CLI
For humans and CI:
uvx aidoctor scan . # zero-install
uv tool install aidoctor # persistent (2026-native)
pipx install aidoctor # isolated
pip install aidoctor # classic / CI
Then:
aidoctor scan . # full repo
aidoctor scan src/ tests/ # specific paths
aidoctor scan --diff # only lines you've changed
aidoctor scan-pr https://github.com/owner/repo/pull/42
aidoctor scan --explain bare-except-pass # docs for one rule
No signup. No API key. No telemetry. Runs entirely on your machine.
What it catches
25 rules across 8 categories. Each rule has a stable ID (bare-except-pass, hardcoded-api-key, range-len-loop) that appears identically in scan output, the skill markdown, and the slash command — so an agent can cite a finding back to you and you can cite a finding back to the agent.
| Category | Rules |
|---|---|
| Dead defenses | bare except: pass, except Exception swallowing, unreachable raise after return, redundant null-check after isinstance |
| Hardcoded secrets | API key / token literals, AWS credentials, JWT-shaped strings |
| Async/sync mismatch | sync I/O in async fn, asyncio.run inside async fn, blocking call in event loop |
| Fake type hints | Any everywhere, missing return type on public fn, generic without TypeVar |
| Stale loop patterns | mutate list during iteration, range(len(x)), time.sleep in tests |
| Performance | nested-loop append, += string concat in loop, repeated dict lookup |
| AI-slop imports | wildcard import, duplicate import, conditional import outside try, import without use |
| Comment-driven decay | TODO/FIXME without ticket, stub comments (# implement this) shipped as code |
Full rule reference: aidoctor scan --explain <rule-id>.
Score
aidoctor scan outputs a 0–100 health score. The score penalizes the number of unique rules tripped, not raw violation count — so fixing one category moves the number, instead of chasing per-line totals.
| Band | Label |
|---|---|
| 90–100 | Healthy |
| 70–89 | Needs work |
| 0–69 | Critical |
Same formula on every machine. Same formula in CI.
Slash commands
In Claude Code, the plugin installs /aidoctor:scan (run a scan + summary). In OpenCode and Gemini CLI, aidoctor install drops a global /aidoctor command. Cursor and Codex don't support custom slash commands; the rules file is the install vector there.
GitHub Action
- uses: ankit-aglawe/aidoctor-action@v1
with:
fail-on: error # error | warning | none
Or call the CLI directly in any workflow:
- run: uvx aidoctor scan . --fail-on error
Pre-commit:
repos:
- repo: https://github.com/ankit-aglawe/aidoctor
rev: v0.1.0
hooks:
- id: aidoctor
Configuration
aidoctor reads [tool.aidoctor] in pyproject.toml if present. The defaults are designed to be useful without any config.
[tool.aidoctor]
exclude = ["migrations/", "vendor/"]
fail-on = "error"
Inline suppression
# aidoctor: disable=hardcoded-api-key
API_KEY = "sk-test-not-real"
Variants:
foo() # aidoctor: disable-line=range-len-loop
# aidoctor: disable-file=stub-comment,todo-without-ticket
Multiple rules: # aidoctor: disable=rule-1,rule-2.
How it differs
| aidoctor | Ruff | Sloppylint | CodeRabbit | |
|---|---|---|---|---|
| Catches AI-author patterns specifically | ✓ | partial | ✓ | ✓ |
| Stable rule IDs | ✓ | ✓ | — | per-customer |
| Installs a skill in your agent | ✓ | — | — | — |
| Runs locally, no cloud | ✓ | ✓ | ✓ | — |
| Free CLI | ✓ | ✓ | ✓ | $24/seat/mo |
| Per-PR scan | ✓ (scan-pr) |
via Action | — | ✓ |
Ruff is the right tool for correctness. aidoctor is the right tool for the specific failure modes LLMs have when they write Python — patterns that pass Ruff and mypy on default settings but break in production.
Leaderboard
How major Python projects score:
| Repo | Score | Top issues |
|---|---|---|
| coming at launch | — | — |
Want your project listed? Open a PR adding it to leaderboard.yaml.
Roadmap
- Claude Code plugin via
/plugin marketplace add ankit-aglawe/aidoctor - Listed on the official Anthropic plugin marketplace
- MCP server (
aidoctor mcp) so Cursor / Windsurf / Codex / Gemini reach the rules over a single transport -
aidoctor learn— propose project-local rules from your git history - PR-delta scoring on GitHub Action
Credits
Inspired by react-doctor by @aidenybai. Built for the era where most Python isn't written by humans anymore.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aidoctor-0.1.1.tar.gz.
File metadata
- Download URL: aidoctor-0.1.1.tar.gz
- Upload date:
- Size: 93.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47149a73392accfbe8e2add4d766217da3cdf7b2321156e03299ee14f792c1a3
|
|
| MD5 |
7ab27135c4899bdaca9934ce0b40ffa1
|
|
| BLAKE2b-256 |
b78c5a822c9ffcc4a46dccafc609d8e1fe2b3a9022ed52ad163ca1bd43c1df74
|
File details
Details for the file aidoctor-0.1.1-py3-none-any.whl.
File metadata
- Download URL: aidoctor-0.1.1-py3-none-any.whl
- Upload date:
- Size: 56.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fc6db9746c25fd9995bc13e0acefee67eaa85943566219b861147c5ab0ca011
|
|
| MD5 |
318f90483ef67467ce7af7d122de41f0
|
|
| BLAKE2b-256 |
98f4d4ad27f4e37227d039c2b543b92c51693fbd611faf0256fd96b642db9f0b
|