Docs
IntentiAI is one command-line tool with two jobs. intentiai audits a repository for patterns that run up an AI bill. intentiai check reviews what a coding agent just changed, before you push.
Install
Nothing to install. Run it with npx from the root of any repository:
npx intentiaiIt needs Node 20 or later. Python 3 is optional: with it, Python files are read with a real parser; without it, they are read line by line and a few rules see less. No API key, account or network access is needed to scan.
Cost audit
npx intentiai [path]It finds every call to a model provider (through the official SDKs, LangChain, LiteLLM, the Vercel AI SDK, Spring AI, LangChain4j, LangChainGo, or plain HTTP to a provider endpoint) and checks it against the rules below. How deep it goes depends on the language:
| Language | What runs |
|---|---|
| TypeScript, JavaScript, Python | Every call site and all 21 rules, with a real parser. |
| Go, Java, Ruby, PHP | Every call site, and the 8 rules that need no deeper analysis: missing caps, oversized models, no budget guard, unprotected endpoints, scheduled jobs, vision calls in loops, batchable work, committed keys. Measured at 96 to 100% of call sites found on 37 real apps. |
| Everything else | Counted and named as not scanned, so a quiet result is never mistaken for a clean one. |
It prints a short summary, uploads the findings, and prints a private link to the full report. The upload is findings only: rule, file, line, summary, fix and the model names it saw. Your source code is never sent. See Privacy for the exact fields.
Every dollar figure is an estimate with its assumptions stated next to it: the model it assumed, the calls per month, the token counts. When the model cannot be read from the code, the report says which model it assumed instead of guessing silently.
Cost audit flags
--local | Audit and print locally. Nothing is uploaded and no link is printed. |
--json | Print the full audit as JSON instead of the summary, for scripts and CI. |
What the audit looks for
Fourteen of the 21 rules cite the published study or incident behind them, linked from the finding in the report.
no-budget-guard | No dollar or token cap anywhere on the path to a paid call. |
guard-conditional-on-env | A spending or abuse guard that only exists when certain env vars are set. |
no-max-tokens | A call with no output cap on a model where long answers are expensive. |
model-oversized | A frontier model doing a short, simple job where a cheaper sibling is likely enough. |
agent-loop-unbounded | An agent or tool loop with no iteration limit. |
retry-storm | Retries on a paid call with no cap, no backoff, or both. |
orphaned-async-job | A billable job polled with no deadline and no way to cancel it. |
full-history-resend | The whole conversation re-sent on every turn, so cost grows with its square. |
recurring-job-llm | A scheduled job that calls a model whether or not anyone is using the app. |
vision-in-loop-uncapped | Image or vision calls inside a loop with no limit on how many. |
reasoning-budget-in-loop | A high reasoning budget on a call that runs many times. |
auxiliary-call-multiplication | Extra model calls (moderation, titles, summaries) multiplying every request. |
cache-storage-leak | Provider-side caches created and never deleted, billed by the hour. |
cache-write-churn | Prompt caching on text that changes every call, so you pay to write and never read. |
result-cache-candidate | The same deterministic call paid for again on every duplicate request. |
sync-batch-candidate | Bulk work sent one call at a time where a batch API costs half. |
sticky-fallback-model | A fallback to a pricier model that never switches back. |
unvalidated-input-to-paid-call | Request fields reaching a paid call with no validation. |
unauthenticated-llm-endpoint | An endpoint anyone can call that spends your model budget. |
client-side-key-exposure | A provider key shipped to the browser. |
hardcoded-api-key | A provider key committed in source. The key is masked in every report. |
Ship Check
npx intentiai check
npx intentiai check --base mainIt reads what changed (uncommitted work against HEAD by default) and runs 21 checks for the mistakes coding agents make after their own tests pass. Findings are ordered by risk, each says what happens to people using your app if it ships, and each names the fix.
It writes a full report to .intentiai/ship-check.html and prints the most serious findings. Nothing leaves your machine unless you add --share.
Ship Check flags
--staged | Only what is staged for the next commit. |
--base <ref> | Compare against a branch or commit instead of HEAD, for example the branch you will open a PR into. |
--json | Print findings as JSON. |
--no-report | Skip writing the HTML report. |
--out <path> | Write the HTML report somewhere else. |
--open | Open the HTML report in your browser when the check finishes. |
--agent [name] | Also review with your own installed coding agent: claude, codex, gemini, or auto. See below. |
--model <m> | The model the agent pass uses. |
--task "…" | What you asked the agent to do. Its claims are checked against the change. |
--share | Upload this result and print a link to it. Off by default, decided per run. |
What Ship Check looks for
test-integrity | Tests deleted, skipped, narrowed with .only, stripped of assertions, loosened in place, or propped up with a sleep; coverage gates lowered. |
migration-safety | Schema changes that lock or rewrite a table, or drop something the running app still reads. |
destructive-ops | Recursive deletes, dropped databases, truncates, unfiltered bulk deletes, force pushes. |
auth-surface | A new endpoint with no visible auth, or a webhook that does not check the sender's signature. |
removed-guard | A validation, permission or rate-limit call deleted without a replacement. |
secrets | Credentials committed in the change. Masked in every output. |
injection-sink | Untrusted data reaching SQL, HTML, a shell, eval or an outbound URL. |
workflow-prompt-injection | Issue or PR text interpolated into a CI script or an AI action. |
env-drift | Code reading an environment variable nothing declares. |
dependency-risk | An import with no matching installed package, the offline sign of a hallucinated dependency. |
dependency-bump | A dependency moved across a breaking version boundary. |
breaking-export | A public function or export removed or re-signed while other code still calls it. |
ops-deltas | Schedules run more often, retries added without backoff, timeouts raised, CI concurrency that does nothing. |
io-in-loop | A database, HTTP or model call made once per loop iteration. |
unawaited-async | An async call whose result, and whose failure, is dropped. |
resource-leak | A file, socket, cursor or interval opened and never released. |
swallowed-errors | An empty catch, except or rescue; an error assigned to _ in Go. |
suppressed-diagnostics | Type or lint errors silenced without a stated reason. |
unfinished-work | TODOs, stubs and placeholder values left in the change. |
debug-leftovers | Debugger statements and stray debug prints in application code. |
scope-creep | CI, infrastructure or generated files touched, or a change too large to review. |
Your own agent
npx intentiai check --agent claude --task "add Stripe webhooks"With --agent, IntentiAI hands the change and its findings to the coding agent you already have installed and signed in (Claude Code, Codex or Gemini CLI) in read-only mode. It runs on your plan, and the report shows what the run cost.
The agent is allowed to do five things, and only these:
- summarize the change and each file in plain English;
- compare what it was asked to do (your
--task) against what the code actually does; - confirm a finding, or rule one out with a stated reason; ruled-out findings stay visible in the report;
- list what to check before and after you deploy;
- report up to five defects of its own, each with a file, a line and the exact line quoted. One is kept only if that line exists in a changed file within three lines of where the agent says, and it does not repeat a deterministic finding. They appear in their own “Found by your agent” section, each marked “checked that the quoted line exists, not that the problem is real.”
This is what catches the mistakes no pattern can: a limit applied to the wrong kind of account, a header replaced instead of merged. It cannot change the severity of a deterministic finding, its own findings are never marked critical, and they never count toward the exit code. If it fails or times out, you get the deterministic result unchanged. The change it reads goes to that agent’s provider under your own account’s terms, not to IntentiAI.
Run it automatically
A check you have to remember to run is a check that gets skipped. Three ways to make it happen on its own:
When Claude Code finishes a task
npx intentiai init claudeThis adds a Stop hook to .claude/settings.json in your project (add --user for every project). When Claude Code says it is done, Ship Check reviews the change, including commits it made but has not pushed. If there are critical or high findings, they go back to Claude with their fixes, and it gets one round to fix them or explain why each is intended before it stops. It never loops, and if the check itself fails, Claude stops normally. To undo it, remove the intentiai entry under hooks.Stop in that file.
When Codex finishes a task
npx intentiai init codexCodex has no hook that can stop it from finishing, so this adds a short section to AGENTS.md asking it to run the check and address critical findings. It is an instruction Codex reads, not something enforced.
Before every push
npx intentiai install-hookInstalls a git pre-push hook that checks everything you are about to push against the branch you push to. A critical finding stops the push; git push --no-verify skips it once. It will not replace a hook you already have unless you add --force.
Connect your computer
npx intentiai loginWithout an account, every upload prints a private link you open to keep the report. Connect the computer once and reports go straight to your account instead: login shows a short code and opens a page where you confirm it. npx intentiai whoami shows which account a computer uses, npx intentiai logout disconnects it, and your Account page lists every connected computer with a button to revoke it.
Exit codes and CI
intentiai checkexits1when there is at least one critical finding,0otherwise, and2on a usage error, so it can gate a pre-push hook or a CI job.intentiai(the cost audit) exits0after a successful scan whatever it finds; use--jsonand your own threshold if you want it to gate.
# in CI, on a pull request
npx intentiai check --base origin/main --no-reportTroubleshooting
The claim link says it has expired
Unclaimed cost reports are deleted after seven days, and shared Ship Checks after two. Run the command again for a fresh link.
The sign-in email link does not work
Open it in the same browser you requested it from; the link is tied to that browser. Each link works once.
“Not scanned: N Kotlin files”
The audit reads TypeScript, JavaScript, Python, Go, Java, Ruby and PHP. Other languages are listed so you know what was not checked. Kotlin, C# and Rust are next: they are measured already but do not yet find enough of the calls to ship.
“This change is too large to review as one change”
The diff is over 64 MB. Point --base at a nearer commit, or check the change in parts.
Something else
Open an issue on GitHub with the command you ran and what it printed.