argot

argot

A local guardrail MCP server that checks agent-written code against a repo's own patterns — learned statistically from its git history, no LLM.

Category
访问服务器

README

<p align="center"> <img src="docs/argot-logo.svg" alt="argot" width="200" /> </p>

<p align="center"> <strong>Your codebase has a voice. argot makes AI code speak it.</strong><br/> <em>AI writes the code. argot harnesses it with the one thing that can't hallucinate: your repo's own history. Statistics, not a second LLM — flagging a dependency you've never used, a function you already wrote, an import that breaks your layering, a test quietly weakened, a convention only your team knows. 100% local, replayable.</em> </p>

<p align="center"> <a href="https://argot.tmonier.com"><strong>argot.tmonier.com</strong></a>  ·  <a href="https://argot.tmonier.com/docs/">Documentation</a>  ·  <a href="https://argot.tmonier.com/benchmarks">Benchmarks</a>  ·  <a href="https://argot.tmonier.com/caught-in-the-wild">Caught in the wild</a>  ·  <a href="docs/research/README.md">Research log</a> </p>

<p align="center"> <a href="https://github.com/get-tmonier/argot/releases/latest"><img src="https://img.shields.io/github/v/release/get-tmonier/argot?color=E67E45" alt="Release" /></a> <a href="https://www.npmjs.com/package/@tmonier/argot"><img src="https://img.shields.io/npm/v/@tmonier/argot?logo=npm" alt="npm" /></a> <a href="https://github.com/get-tmonier/argot/actions/workflows/ci.yml"><img src="https://github.com/get-tmonier/argot/actions/workflows/ci.yml/badge.svg" alt="CI" /></a> <a href="https://github.com/get-tmonier/argot/blob/main/LICENSE"><img src="https://img.shields.io/github/license/get-tmonier/argot?color=E67E45" alt="License" /></a> <img src="https://img.shields.io/badge/status-alpha-5B8DEF" alt="Status: alpha" /> <img src="https://img.shields.io/badge/rust-single%20static%20binary-DEA584?logo=rust&logoColor=white" alt="Rust" /> <img src="https://img.shields.io/badge/100%25-local%20%C2%B7%20no%20cloud-brightgreen" alt="100% local, no cloud" />  · <a href="https://argot.tmonier.com/docs/languages/">11 languages →</a> </p>

<p align="center"> <a href="https://argot.tmonier.com/#film"><img src="landing/public/argot-film-poster.jpg" alt="Watch the argot launch film" width="220" /></a> <br/> <em>🎬 <a href="https://argot.tmonier.com/#film">Watch the 45-second launch film</a></em> </p>


Type checkers ask "is this valid?" argot asks the question that used to live in code review: "is this how we do it here?" — and catches AI code that's flawless, type-correct, lint-clean, and still doesn't belong. It answers with statistics on your repo's own history — the statistical core deterministic and replayable, everything local — never a second LLM judging the first.

It also asks a second question no other tool asks: did the AI play fair? When an agent can't make a failing test pass, the cheapest path to "done" is to make the test stop looking. argot reads both sides of every diff and pairs a weakened, disabled, or deleted test with the production change it covers.

Five learned detectors — plus the rules only your repo could write

Rule It catches
🚫 foreign-import + friends a dependency, API, or idiom your repo has never used "we don't do it this way here"
♻️ redundant a new function that reinvents one you already have "you already have this"
📍 misplaced the right code, filed in the wrong place "this doesn't belong here"
🧱 layering an internal import that reverses your architecture "we never cross this boundary"
🧪 test-deleted + friends a test quietly weakened, disabled, or removed alongside the prod change it covers "don't game the tests"
📜 your own rules the conventions only your repo has — scripted, no recompile "here's exactly how we do it"

The first five are learned from your git history. The sixth is written by you — and it's the part of every linter config your team actually cares about.

Get started

# install (single static binary — no Python, no Node)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/get-tmonier/argot/releases/latest/download/argot-installer.sh | sh

Windows: powershell -c "irm https://github.com/get-tmonier/argot/releases/latest/download/argot-installer.ps1 | iex" · npm: npm install -g @tmonier/argot

Sixty seconds of proof, zero setup, on your own history:

argot audit      # ⏪ what did AI sneak into your last 50 commits?

audit fits the voice as it was 50 commits ago (in a temp worktree — your tree stays untouched), rescores everything since, and attributes every finding to its introducing commit — ai-assisted / human / unknown, from concrete commit markers only:

━━ argot audit ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  last 50 commits · 52% carry AI markers · 1 finding would have met review

  Worst offender — commit cae8349 · ai-assisted
  ! landing/src/pages/llms-full.txt.ts:L1-32 · foreign-import
      ↳ astro (L1), astro:content (L2) — 0 of 49 module specifiers…
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

The terminal card ends with a copy-paste share caption, and argot audit --format html is a screenshot-ready card — post your score.

Then fit today's voice so check raises these before they merge:

argot init       # learn this repo's voice (~25 s on a 1,100-file repo)
argot check      # score your working changes against it

Accuracy is a function of setup — argot learns from what it's allowed to see. Best path: npx skills add get-tmonier/argot, then /argot-setup in your coding agent (Claude Code, Cursor, 70+ agents) reads your repo, excludes what shouldn't shape the voice, and verifies the catch. Full guide: Setup · Getting started.

Claude Code — one install for everything. The argot plugin bundles the five skills, the MCP server (argot mcp — proactive voice context while your agent writes), and an opt-in, non-blocking pre-write guardrail that asks before a foreign dependency lands:

/plugin marketplace add get-tmonier/argot
/plugin install argot@argot

Other agents (Cursor, Codex, 70+): npx skills add get-tmonier/argot.

Demo

<p align="center"> <img src="docs/demo/demo.gif" alt="argot check flagging a foreign Django-style view in an all-FastAPI codebase" width="760" /> </p>

A PR adds a Django-style view to an all-FastAPI codebase. mypy and ruff are silent — the framework it reaches for is one this repo has never imported:

argot check · 1 hunk above threshold (1 foreign)

fastapi/receipts.py
  !  L1-L10         1.00  foreign  · staged · foreign-import [94a92c256ea1]
     ↳ django (L1) — 0 of 74 module specifiers in repo
       common here: fastapi (357×), pydantic (129×), typing (129×) (+7 more)
  1 | from django.views import View
             ^^^^^^

redundant names the function you already have (↳ duplicates slugify (src/utils/text.py:14) — similarity 0.86), misplaced names where the code belongs, layering names the direction an import reverses, and every line is your repo's own evidence. Full anatomy: Reading the output · What it catches.

Your conventions, as rules

Every team has conventions no generic linter ships: "presentational components take props — they don't fetch", "files are parsed through our loader, never a raw JSON.parse", "one HTTP client per repo". They live in review comments and onboarding docs — until an AI agent, who read neither, merges around them. With argot they're repo-local rules: a TOML manifest + a small sandboxed script in .argot/rules/, versioned with your code, loaded at run time — no plugin build, no recompile, one rule format across all 11 languages.

And they can do what no classic linter structurally can. A linter sees one version of one file; argot hands your rule both sides of the diff — so you can write rules about what a change removed:

# .argot/rules/no-dropped-endpoints/rule.toml
[rule]
schema = 1
name = "no-dropped-endpoints"
description = "removing a public endpoint requires a deprecation cycle — catch the route that silently disappears in a diff"
severity = "error"
languages = ["typescript", "javascript"]
// check.rhai — a route that existed before this change, and is gone now
const ROUTES = "(call_expression function: (member_expression property: (property_identifier) @verb)
                arguments: (arguments (string (string_fragment) @path)))";
let now = [];
for m in ts_query(ROUTES) { if m.capture == "path" { now.push(m.text); } }
for m in ts_query_old(ROUTES) {
    if m.capture == "path" && !now.contains(m.text) {
        report(m.line, "endpoint '" + m.text + "' removed without a deprecation cycle — see docs/api-lifecycle.md");
    }
}

No ESLint plugin can express that rule — there is no "old side" in a linter. And because argot fits your history, a rule's allowlist can be your own git log: import_attested("moment") asks "has this repo ever used this date library?" — no list to hardcode, no list to maintain. Rules run on changed files only (adopting one creates zero backlog noise), and their findings are suppressed, configured, and rendered exactly like built-in rules. argot rules test is the red/green authoring loop. Full reference + worked examples: Custom rules.

Rules an agent can't game

An AI agent that can't satisfy a check will reach for the next-cheapest green: mute the rule, downgrade it in a local config, --rule it=off, or — for a custom rule — just rewrite the script that caught it. Lock the rule and every one of those doors closes:

[rules]
layering = { severity = "error", locked = true }
custom   = { severity = "error", locked = true }   # lock every repo-local rule

A locked rule (opt-in, from the committed argot.toml only):

  • freezes its severityargot.local.toml and --rule overrides are refused;
  • refuses every suppression surface for its findings — inline # argot: ignore, [[mute]], and [exclude].paths don't apply;
  • and — the teeth — weakening the lock is itself a finding. rule-tampered (group governance, pinned error, unsuppressable) reads both sides of the diff being checked and fires when the change removes a lock, downgrades a locked severity, adds a [[mute]] on a locked rule, or edits a locked custom rule's script — with a loud run-level warning your CI surfaces (a PR annotation under --format github).

Tamper-evidence, not tamper-proofing — the same philosophy as the test-integrity rules: an agent can touch the alarm, but touching the alarm is the alarm. The one quiet way to relax a locked rule is a committed argot.toml diff a human reviews. Guide: Locked rules.

Configure it like any linter

Every rule (built-in or yours) defaults through argot.toml [rules]error / warn / off, per rule or per group — or per run via --rule layering=warn. A [rules] entry can also scope a rule to paths (layering = { include = ["src/**"] }). Excludes are gitignore-style [exclude].paths; inline # argot: ignore-next-line rule=… — reason and argot mute <hash> give line-level and durable committed acceptances. Guides: Configure · The commands.

argot vs. the tools you already run

Type checker Linter Copilot · SAST argot
Catches invalid code ~
Flags what's foreign to this repo
Flags a function you already have
Flags code filed in the wrong place
Flags an import that breaks your layering
Flags a test quietly weakened to game a failing suite
Enforces your team's own conventions, cross-language, on the diff ~
Locked rules an agent can't mute, override, or rewrite unnoticed
Audits merged history · attributes findings AI vs human
Learns from your history · runs 100% local

argot is additive: it sits after your type checker and linter and catches the one thing they can't — code that's valid and lint-clean but unlike anything your team has written. It's the harness around AI output, built from the one thing that can't hallucinate: your repo's own history.

Benchmarks

Honest, leak-free numbers, measured by the real fit → check pipeline — foreign fixtures spliced into real host files; false alarms counted on a temporal holdout the model never saw:

  • Foreign catch — 595/605 (98%) when the foreign symbol is visible in the diff · false alarms 0.29% of 22,513 real hunks (worst corpus 1.46%)
  • Architecture — 244/252 (96.8%) caught · 0/140 controls flagged · ≤2.7% over-fire on replayed real history
  • Reinvention — median 89% at ≤4.5% false fires per hunk · Misplacement — 85–99% (median 96%) at ≤1.2%, where the repo has separable architecture
  • Test-integrity — 144/153 (94.1%) gaming tactics caught · 0/102 legitimate-refactor controls · 1.12% of 5,268 replayed accepted test-touching commits flagged at gating severity

One documented limit: masked foreign — a foreign symbol whose name collides with one you already use — is statistically invisible to a voice model. We publish that number rather than hide it. And the method, stated plainly: catch rates are measured on fixtures we authored under a pre-registered rubric frozen before scoring; false alarms are counted on real commits the model never saw. Independent validation is welcome — that's what the reproducible harness is for. Per-language and per-corpus tables, methodology, confidence intervals: benchmarks page (CI-fed, can't drift from what ships). Want a language validated? Open an issue.

Numbers are one thing; real diffs are another. Caught in the wild collects verified findings from running argot over the last year of history on 33 real open-source repos (dagster, hono, rich, saleor, faker, and more) — each one adversarially attacked by a reviewer briefed to disprove it, and every one survived.

CI

- uses: get-tmonier/argot@main   # non-blocking voice score on every PR

--format github prints inline PR annotations; --format sarif feeds code scanning; --format json is a stable schema. Add publish-badge: true (with contents: write) for a live README badge — argot · N% in-voice, updated on every push. Copy-paste setups incl. pre-commit: the CI guide.

How it works

Five learned detectors, one source of truth — your git history — plus the rules you script yourself. A statistical voice model (two frequency tables + a callee-cluster partition — no neural net) catches foreign imports, callees, and token shapes; a local code-embedding model (jina-code via statically-linked llama.cpp) catches reinvention and misplacement; a module-dependency graph catches layering reversals; a test-inventory diff catches gamed tests. Fit in seconds, check in milliseconds, nothing leaves your machine — and nothing generates: every verdict is a statistic you can replay. Full detail: How it works · The scoring model · Performance · experiment log in docs/research/.

Contributing

Issues and PRs welcome — start with CONTRIBUTING.md:

git clone https://github.com/get-tmonier/argot && cd argot
just build       # cargo build --release -p argot → target/release/argot
just verify      # cargo fmt --check + clippy -D warnings + cargo test

Acknowledgements

argot is benchmarked against real repositories used as read-only corpora — cloned at benchmark time, never redistributed, each under its own license, none affiliated with argot: FastAPI, rich, faker, Saleor, Wagtail, Dagster, Scrapy, Hono, Ink, faker-js, Excalidraw, Outline, Express, Commander.js, ESLint, GitHub CLI, Hugo, ripgrep, bat, Guava, JUnit 5, PowerShell, Jellyfin, redis, curl, RocksDB, fmt, Homebrew, RuboCop, Laravel, and Composer.

Built on tree-sitter (11 grammars), libgit2 via git2, HuggingFace tokenizers (UnixCoder BPE), Rhai (scripted rules), clap, Serde, and cargo-dist. The semantic layer links llama.cpp (MIT) statically via llama-cpp-2; its model is jina-embeddings-v2-base-code by Jina AI (Apache-2.0), fetched on first use as a Q4_K_M GGUF quantization (a derivative work under Apache-2.0 §4) from the semantic-model-v1 release. argot is not affiliated with, nor endorsed by, Jina AI.

Privacy

argot runs 100% locally — no telemetry, no account, your code never leaves your machine. Full policy: argot.tmonier.com/privacy.

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选