The harness for AI-written code · statistics, not a second LLM · 100% local

Lint the rules you never wrote down.

AI writes the code. argot harnesses it with the one thing that can’t hallucinate: your repo’s own history. Deterministic, measured, local.

97.3% of foreign patterns caught · 0.25% of real edits flagged

checks a diff in200 ms

A concrete example

Type checkers ask if it compiles. argot asks if it’s yours.

Clean, type-correct PRs can still be foreign to your repository. This is its real output.

  • mypystrict — passes
  • rufflint-clean
  • argotflags what doesn’t fit
argot check
argot check
fastapi/receipts.py
!L1-L10foreignforeign-import[94a92c256ea1]
django — 0 of 74 imports in this repo
repo reaches for: fastapi · pydantic · starlette
1from django.views import View

Valid Python — but a framework this repo has never imported. The evidence shows what it reaches for instead.

See it on real repos

Why this matters

An agent that can’t fix the code will “fix” the test.

A green check can hide a weakened test. argot pairs it with the changed code and names both.

  • skip it@pytest.mark.skip("flaky")
  • gut itassertions removed, test kept
  • retarget itexpected 429 → becomes 200
  • delete ittest gone, code stays
the green checkmark, audited
# your agent, 40 minutes ago:
   Done — 42 passed, 0 failed(was: 3 failing)
 
argot check
  tests/test_rate_limit.py
  ? L214  1.00  suspicious · staged · test-disabled [c48f0a1de923]
↳ test `test_rate_limit_429` disabled — skip/ignore marker added;
  this change also modifies middleware/rate_limit.py
  214 | @pytest.mark.skip(reason="flaky since limiter rework")
  215 | def test_rate_limit_429():

154/164 (93.9%) — detector-specific fixture catch; controls and accepted-history results are separate. Read the detector scope and controls.

Evidence you can reproduce

Audit accepted changes before making it a habit.

argot audit compares accepted changes with the repository history before them. Findings are prompts to inspect, not defect verdicts.

argot audit
argot audit
━━ authored proof receipt · argot 0.2.89 · last 1 commit ━━
  1 commit audited · 1 finding would have prompted review
    voice  1  code foreign to how this repo writes
  Worst offender— commit 705db9c · human
  ! src/receipt.py:L1-10  rare-tokens
authored two-commit fixture · raw JSON and checksum are committed
import, class, def — zero-usage tokens in the fitted fixture

Then run argot init and choose a recurring check path.

Measured, not promised

Honest numbers, leak-free by construction.

97.3%

visible foreign patterns

620/637 (97.3%) — detector-specific fixture recall; not a product-wide accuracy claim. Fixture recall; the changed symbol is visible in the diff.

36 corpora / 12 languages / visible foreign-import and foreign-api fixture symbols after excluded-host purge · d1007f50; generated_at=2026-07-28

97.1%

layering violations

264/272 (97.1%) — detector-specific real recall; control result is separate. Authored internal layering violations across 25 corpora and 12 languages.

25 corpora / 12 languages; authored internal layering violations · 7886a7967c6fe5b822a249083c7871894db1efcf; generated_at=2026-07-20

93.9%

test-integrity gaming edits

154/164 (93.9%) — detector-specific fixture catch; controls and accepted-history results are separate. Authored production fit-to-check gaming fixtures.

23 corpora / 12 languages; authored test-gaming fixtures, production fit→check · 1b0de32d; just integrity-verify, 2026-07-28

One static binary. Twelve languages — each with its own tree-sitter adapter and its own learned model:

  • Python
  • TypeScript
  • JavaScript
  • Go
  • Rust
  • Java
  • C#
  • C
  • C++
  • Ruby
  • PHP
  • Pascal

Recall on patterns planted in real files; false alarms on a temporal holdout. Even the structural blind spot — masked foreign — is published, not hidden.

Full per-repo numbersSee it caught in the wild

How it works

From audit to a recurring check you choose.

Run argot init, then choose the CLI, skills, a commit hook, or a GitHub Action. The Claude plugin adds a narrow pre-write prompt — not a full acceptance-time check.

Install the CLI

Add agent skills

seven on-demand skills for compatible hosts:

  • /argot-setupreads your tree, writes argot.toml, verifies the catch
  • /argot-refreshreviews scope and mutes, then refreshes the learned snapshot
  • /argot-checkscores each diff, flags what’s foreign — never blocks
  • /argot-review-prreviews one PR against your repo’s voice, no checkout
  • /argot-setup-cia non-blocking voice score on every PR
  • /argot-write-ruleturns a convention you state into a tested rule
  • /argot-suggest-rulesfinds your conventions, codifies one

The Claude plugin adds optional MCP context and a narrow, fail-open pre-write prompt; agents still decide when to call Argot. Get the plugin →

Or drive the CLI by handthe CI guide ↗

terminal
$ argot init
Step 1/2: training voice model …
Step 2/2: calibrating threshold …

Corpus
  1129 files · 503 learned · 626 tests/docs skipped
Verdict: Ready

Snapshot → .argot/ · voice · semantic index · health
Review + commit → argot.toml · .argot/
Next:  argot check

The learned snapshot is committed; caches stay local. CI reads the base branch copy and never fits.

The whole model, in one glance

Learn once. Share one baseline. Refresh only when the repo truly moves.

Argot’s learned state is a reviewed snapshot in Git, not a hosted service. Every developer, agent, and PR compares against the same repository memory.

1local · once

Learn the repository

argot init learns the voice, semantic neighbours, architecture, and test signals on your machine.

nothing uploaded · model ships in the binary
2reviewed · shared

Commit the baseline

Review and commit argot.toml + .argot/. It is repository-specific learned state, like a lockfile for checks.

usually a few MB to a few tens of MB
3local + PR

Check against the same memory

Local tools, agents, and CI read that snapshot. A PR is judged against the base branch, so it cannot teach itself.

advisory by default · CI never fits
4only when useful

Refresh deliberately

After material accepted drift, status recommends /argot-refresh: review changed scope and mutes, fit locally, recommit.

data-driven · no fixed commit cadence
Docs churn stays quiet. No cron, no “every 10 commits” chore, no hidden training.See the lifecycle in detail →

Integrations

A workflow-configured PR or push signal.

The GitHub Action reads the committed base snapshot and is non-blocking by default. Intentional divergence remains a human decision, recorded as an audit trail.

argot reviewadvisory · not a merge gate
2 review decisionsacross 10 scanned hunks

Start here: open each row in the review queue.

🔎 Review queue🔴 2 error
rare tokenscrates/argot-cli/src/voice_diff.rs:202–282

Evidence: option, highlighted, Move — unfamiliar vocabulary here.

Review: rewrite in the repository’s established form if unintended.

unfamiliar calleecrates/argot-core/src/compose.rs:1–14

Evidence: Lazy::new is not used by similar code here.

Review: compare the call with the repository’s established API.

💬 Prompts for review, not proof of defects.

🧭 Fit health🟢 fresh
Snapshot healthy· no maintenance needed
Adaptive drift: 0 / 100 · base snapshot: main · CI never fits.

Findings land on the PR. Snapshot health stays visible in the same summary.

Under the hood

Semantic understanding. No generative LLM in the core.

Four local engines, one static Rust binary — model included, nothing fetched — all grounded in your git history.

A code-embedding model inside the binary

A 15.6 MB table argot distilled from a code encoder turns every function into a vector — how argot knows you already wrote this. Nothing to download, no GPU, no cloud: it ships compiled in and works air-gapped.

A statistical voice model

Two frequency tables and a callee clustering — the imports, callees, and token shapes your repo actually uses.

An architecture graph

Your module-dependency topology. A new edge that reverses the established direction is flagged with the direction it breaks.

A test-inventory diff

tree-sitter tracks what every test asserts. A test skipped, gutted, or deleted beside a prod change gets paired and named.

0.2s
to check a diff
0.6s
when it defines new functions
25s
first fit, 1,100-file repo
4s
to refresh — embeddings are reused

Measured on FastAPI, laptop CPU. Single static binary — no Python, no Node, no model download, no GPU.

Advanced capabilities

See your conventions — then enforce them.

argot conventions finds the shared API and where code belongs. Turn one convention into a small, testable rule.

  • Discovered, not guessedargot conventions lists what your repo already does — its shared API, and where each kind of code lives — so a rule starts from what argot found.
  • Two-sidedts_query_old sees what a change removed — a rule no classic linter can even express.
  • History-awareimport_attested("moment") asks “have we ever used this?” — no other linter can.
  • Test-drivenargot rules test runs your fixtures — the red/green authoring loop.
  • Tamper-evidentlocked = true freezes a rule; a diff that mutes, downgrades, or rewrites it trips rule-tampered — pinned error, unsuppressable, a loud PR annotation.
Write your first rule →
$ argot conventions

where each kind of code lives — learned from your layout

migrations/queryRunner · addColumn100%
*.schema.tsz.object · validate96%
services/db.transaction · publish92%
controllers/req · res · next98%
.argot/rules/no-dropped-endpoints/severity: error
// check.rhai — a route that existed before
// this change, and is silently gone now
let now = [];
for m in ts_query(ROUTES) { now.push(m.text); }
for m in ts_query_old(ROUTES) {
  if !now.contains(m.text) {
    report(m.line, m.text + " removed —
      deprecate first (docs/api-lifecycle.md)");
  }
}
$ argot rules test no-dropped-endpointsok fires-on-removal · ok quiet-on-refactor

Add the layer your CI is missing.

MIT-licensed open source. Audit first, then choose the recurring check that fits your workflow.