spendlint
Catch the code that inflates your LLM bill, before it ships.
spendlint reads your agent code and points at the patterns that quietly multiply token spend: prompts that never hit the cache, system prompts that change on every call, agent loops with no limit, retries that never stop, and cost reports that miss cached tokens. It works on Python and TypeScript/JavaScript, installs in seconds, and has no dependencies.
On a pull request it only speaks up about the lines that pull request adds, right where you review them. Your code never leaves your machine or your CI runner.
Built by Vernia. Free while we are in early access.
Get started
In GitHub Actions
Add .github/workflows/spendlint.yml:
name: spendlint
on: pull_request
permissions:
contents: read
jobs:
spendlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: vernialabs/spendlint@v0
Findings show up as annotations on the changed lines, with a summary on the run page. Every option (rule selection, confidence threshold, failing the build, SARIF for code scanning) is in docs/ACTION.md, and there is a complete example workflow.
On your machine
pip install spendlint
spendlint . # scan a project
spendlint . --diff pr.patch --fail-on warning # only lines a diff adds; exit 1 on warnings
spendlint . --format sarif --out spendlint.sarif
Configuration, exit codes and inline ignores are in docs/USAGE.md.
What it catches
| Rule | What it flags | Severity |
|---|---|---|
R-ACCT-001 |
Cost computed from token counts that ignore cached-token fields | warning |
R-CACHE-001 |
Anthropic requests with no prompt caching anywhere in the repo | warning |
R-CACHE-003 |
A timestamp, uuid or path inside the system prompt, which breaks the cache | warning |
R-LOOP-001 |
Agent loop around an LLM call with no step limit | warning |
R-LOOP-002 |
Retry on an LLM call with no stop condition | warning |
R-CTX-008 |
Pretty-printed JSON sent in a prompt | info |
R-CALL-004 |
Embeddings requested one item at a time inside a loop | info |
R-MEDIA-001 |
Image detail hard-coded to high | info |
R-OUT-001 |
Chat completion with no output token cap | info |
R-MODEL-001 |
Frontier model hard-coded for a cheap sub-task | info |
Every rule comes from a real cost bug that an open-source agent team found and fixed. spendlint reads code, not invoices, so treat each finding as a pointer worth a second look in review.
What's next
spendlint is the first product from Vernia. Next up are Vernia Reason, a reasoning harness that reviews pull requests with the context of the whole repository, and Vernia Ledger, an agent that connects to your providers and billing to tie every dollar to a feature and a customer. Want early access? Write to ishan.upadhyay.iitb@gmail.com.
Telemetry
spendlint keeps anonymous usage counts so we can see which rules help and where they get in the way. Here is exactly what that means:
- What is recorded: spendlint version, Python version, operating system, CI provider, how many files were scanned per language, how many findings each rule produced, run time, exit code, the hour of the run, and a random install id.
- What is never recorded: your code, file names, paths, repository names, or anything that identifies you.
- Where it goes: a local file you can read at any time with
spendlint telemetry show, and Vernia's collector att.vernia.in, which stores only these counts (not your IP address). Its source is in collector/. SetSPENDLINT_TELEMETRY_URL=noneto keep everything local. - In CI: off by default. Turn it on with
SPENDLINT_TELEMETRY=onor the Action'stelemetry: oninput. - Turning it off:
spendlint telemetry off,SPENDLINT_TELEMETRY=off, orDO_NOT_TRACK=1. - First run: spendlint prints this list once before it records anything.
The full schema is in docs/telemetry.md. A paid plan with telemetry fully disabled is on the way for teams that need it.
License
spendlint is source-available under the PolyForm Small Business License 1.0.0. It is free for individuals and for companies with fewer than 100 people and under US$1 million in annual revenue (the license has the exact terms). Larger organisations need a commercial license; see COMMERCIAL.md.
Contributing
See CONTRIBUTING.md. Run the tests with:
python -m spendlint.test_rules && python -m spendlint.test_cli && python -m spendlint.test_telemetry
Metadata
Release files for spendlint 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| spendlint-0.1.3.tar.gz | 44.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spendlint-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 93.3 kB
Release files / spendlint-0.1.3.tar.gz
| Download URL | spendlint-0.1.3.tar.gz |
|---|---|
| Size | 44.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
43dc5f13eeb6ec7b8c7a0b1d0c00ec577aa12df6a5db4f470b762beb9ff69f24
|
|
BLAKE2b-256 checksum How to use checksums |
0e49f09ccbc180f1de34f9039d101d540c402ea4e5f92728942eed6c702aa521
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / spendlint-0.1.3-py3-none-any.whl
| Download URL | spendlint-0.1.3-py3-none-any.whl |
|---|---|
| Size | 49.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a9a223e72fd28a2343ef0a884733fc981eca72fd13caf7b31d538f1179f9f6b5
|
|
BLAKE2b-256 checksum How to use checksums |
cd1a935e8c0730c894891f5e00f3948c9a8449f4d652ea1a47b21e2713b2093b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for spendlint 0.1.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for spendlint-0.1.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.