Catch the LLM/AI calls you didn't need. A fast, deterministic linter that flags LLM API calls where plain code is simpler, cheaper, and more reliable.
Project description
overllm
Catch the LLM/AI calls you didn't need.
overllm is a small, fast linter with one job: find the places in your code where you call an AI model to do something plain code does better. You called GPT to parse a date. You called a model to extract JSON that json.loads already handles. You are paying latency, money, and nondeterminism for a regex.
It reads your code with Python's own ast module. No model runs, no network, no API key. Same code in, same result out. Fast enough for a pre-commit hook.
Everyone else lints the code the AI wrote. overllm catches where you are paying an AI to do what a library already does.
Install
pip install overllm
Use it
overllm . # scan the current project
overllm src/ # scan a folder
overllm app.py # scan one file
Example output:
app.py:42:5 llm-mechanical LLM call asks the model to sort
resp = client.chat.completions.create(model="gpt-4o", messages=[...])
-> use sorted()
app.py:88:1 llm-in-loop LLM call inside a loop: one API round-trip per iteration
completion(model="gpt-4o", messages=[{"role": "user", "content": f"tag {x}"}])
-> batch the inputs into a single call, cache repeated results, or use a function
2 needless LLM calls in 1 file.
overllm exits non-zero when it finds something, so it gates a commit or a CI check. Pass --exit-zero to report without failing.
Rules
Every rule fires only on a concrete code pattern, and every finding names the deterministic replacement. It stays silent when it is not sure.
| Rule | Fires when | Suggests |
|---|---|---|
static-prompt |
The user prompt is a compile-time constant, no variables. The input is fixed, so the call buys nothing. | precompute or cache the result |
llm-extraction |
The prompt asks the model to extract an email, URL, date, or number. | a regex, datetime, or urllib.parse |
llm-mechanical |
The prompt asks for a mechanical transform: sort, reverse, count, sum, deduplicate, change case, base64, arithmetic on literals. | the one-line stdlib equivalent |
llm-in-loop |
An LLM call runs once per loop iteration (real N calls, not streaming). | batch, cache, or move it out of the loop |
prompt-injection |
Untrusted input (a web request, CLI arg, or input()) flows straight into the prompt. |
keep it in a separate user message, validate it, constrain the model |
It detects calls to the OpenAI, Anthropic, Google, Mistral, Cohere, Groq, LangChain, LiteLLM, and Ollama SDKs, and raw HTTP requests to those hosts.
Silence a false positive
resp = client.chat.completions.create(...) # overllm: ignore
resp = client.chat.completions.create(...) # overllm: ignore=llm-in-loop
Put # overllm: ignore-file at the top of a file to skip the whole file.
Configure
In pyproject.toml (Python 3.11+):
[tool.overllm]
ignore = ["llm-in-loop"]
exclude = ["examples/", "migrations/"]
Or on the command line: --select, --ignore, --exclude via config, --config PATH.
Pre-commit hook
In .pre-commit-config.yaml:
repos:
- repo: https://github.com/theadamdanielsson/overllm
rev: v0.1.1
hooks:
- id: overllm
GitHub Action
overllm ships an Action that scans a pull request and leaves one grounded comment. It stays silent when there is nothing to say.
name: overllm
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: theadamdanielsson/overllm@v1
with:
paths: "."
Other output formats
overllm --format json . # machine-readable
overllm --format sarif . # upload to GitHub code scanning
overllm --format markdown . # the PR-comment body
Why not just use an AI code reviewer?
AI reviewers and AI-slop linters look at the code the model produced: comments, dead code, structure. None of them ask the question overllm asks, which is whether you needed the model at all. It is a different axis, and it is one plain static analysis can answer with high precision and zero cost.
License
MIT © Adam Danielsson
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
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 overllm-0.1.2.tar.gz.
File metadata
- Download URL: overllm-0.1.2.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dee98aad58d13bd5ba03323516f32457d6dc0133858ac9eead59a0868e691ea8
|
|
| MD5 |
7e7b4c844400905efc74ebfaeda79ed3
|
|
| BLAKE2b-256 |
a9b0dd8d5d50069f4b3cd5c7a924e4d5a583d5d92a934325b24555193eca5472
|
Provenance
The following attestation bundles were made for overllm-0.1.2.tar.gz:
Publisher:
publish.yml on theadamdanielsson/overllm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
overllm-0.1.2.tar.gz -
Subject digest:
dee98aad58d13bd5ba03323516f32457d6dc0133858ac9eead59a0868e691ea8 - Sigstore transparency entry: 2064145556
- Sigstore integration time:
-
Permalink:
theadamdanielsson/overllm@d214e4660ee9970ecba1e80542ebf178b61377e7 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/theadamdanielsson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d214e4660ee9970ecba1e80542ebf178b61377e7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file overllm-0.1.2-py3-none-any.whl.
File metadata
- Download URL: overllm-0.1.2-py3-none-any.whl
- Upload date:
- Size: 19.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7816df210316a0ffd029a5575ea8c35b4f2956a0c9cee35d910940c23fba480a
|
|
| MD5 |
c93a05c9540102a59ad78d47d8d57cc9
|
|
| BLAKE2b-256 |
1548592daf0523c3a58ff6cd00a352ab5f15a119e35beee2471ddc6fb4abea42
|
Provenance
The following attestation bundles were made for overllm-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on theadamdanielsson/overllm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
overllm-0.1.2-py3-none-any.whl -
Subject digest:
7816df210316a0ffd029a5575ea8c35b4f2956a0c9cee35d910940c23fba480a - Sigstore transparency entry: 2064145583
- Sigstore integration time:
-
Permalink:
theadamdanielsson/overllm@d214e4660ee9970ecba1e80542ebf178b61377e7 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/theadamdanielsson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d214e4660ee9970ecba1e80542ebf178b61377e7 -
Trigger Event:
release
-
Statement type: