Inspect · Verify · Approve

The evidence layer for AI coding agents

Your agent can change forty files in a minute. Nothing on your machine can tell it what those changes reach — so it reads, guesses, and sounds certain either way. Euthynos answers structurally, and names the boundary of every answer.

npm install -g euthynos
See what it answers
Euthynos - Deterministic MCP server: what your change breaks, offline | Product Hunt

agentI'm about to change serialize. What reaches it?

9 transitive callers of serialize:

  d1 fetch — src/client/client.ts:58
  d1 generateCookie — src/helper/cookie/index.ts:78
  d2 hc — src/client/client.ts:137
  d2 setCookie — src/helper/cookie/index.ts:99
  d3 testClient — src/helper/testing/index.ts:21
  d3 deleteCookie — src/helper/cookie/index.ts:141
  d3 cacheLanguage — src/middleware/language/language.ts:221
  d4 detectLanguage — src/middleware/language/language.ts:238
  d5 languageDetector — src/middleware/language/language.ts:292

For the exact call-site lines with their source: find_references({ symbol: "serialize" }).

Watch it run

One command, on a repository you can check.

A recording of real output, not a mock-up. Clone hono at 26de7313, run the same command, and the numbers should match.

hono — 382 files
$

        

Health 68 is not a grade to fix — it is five measured signals with their inputs named. Leverage 36 says most exported surface has few callers. Locality 88 says related changes already land together. These 382 files scan once; the index is content-addressed, so the next scan only re-reads what changed.

The shift

Writing code stopped being the bottleneck. Verifying it started.

An agent that can produce a refactor in seconds still has no structural picture of the repository it is editing. It compensates the only way it can — by reading files until the context window fills.

01

Reading is not understanding

Opening forty files tells an agent what the code says, not what depends on it. Inbound edges are invisible from the file you are looking at.

02

Confidence is not calibrated

A model that missed a caller sounds exactly like a model that found them all. Nothing in the transcript distinguishes the two.

03

The reviewer is now the human

When generation is cheap, the scarce resource is a person deciding whether a change is safe to ship — with whatever evidence they were handed.

The evidence model

It refuses to tell you your change is safe.

Euthynos is a static analyser. It sees imports, declarations and call edges — not reflection, not dynamic dispatch, not production. So it never claims otherwise. Every answer carries the boundary of the method that produced it, and every empty answer says what was not examined rather than implying nothing exists.

Claims the engine will not make

this change is safe all references no other consumers fully tested unused — safe to delete no impact mathematically proven

These are enforced by the test suite, not by style guide. A change that lets any of them reach a user is a failing build.

Tiered, and labelled

Structural resolution establishes facts. Name conventions and text matches discover candidates. The two are never presented as the same thing.

Exclusions are stated

Files skipped for size, ignore rules or parse failure are counted and reported. A narrowed answer says it was narrowed.

Capabilities

Twenty-three read-only tools, over MCP.

Your agent calls them the way it calls any other tool. Nothing is written to your repository except a gitignored index that is safe to delete at any time.

QuestionToolEvidence it returns
What reaches this function?callers_ofTransitive callers with depth and location
What does my edit touch?check_my_changesChanged symbols, blast radius, tests, stated scope
Which tests relate to this?tests_forRoute-labelled test files — never a coverage claim
Does this already exist?similar_logic_existsNear-duplicate implementations with both spans
What is this repository?repo_mapModules, sizes, structural signals, health
Did I cross a boundary?boundary_checkDeep-import violations introduced by the diff

Plus symbol and reference lookup, callees, module dependencies and dependents, path-between, context bundles, and span-accurate source reads. 16 languages parse — call-graph resolution is strongest in TypeScript.

Measured, not asserted

We preregistered the benchmark before running it.

Answer keys frozen by commit. Sessions gated. Recall hand-graded against those keys before anyone looked at the transcripts. Here is what it showed — and what it did not.

42 / 42
Required answer-key items recalled — identical with and without Euthynos, on the three fully-measured tasks.
13–31% fewer
Fresh input tokens on those same tasks, per-task medians, for the same graded answers.
21 / 42
Sessions that survived the preregistered validity rules. The other 21 are reported, not hidden.
Grouped bar chart of median fresh input tokens per task. callers: baseline 70,878 versus euthynos 49,476, 30 percent fewer. similar-logic: 33,429 versus 29,120, 13 percent fewer. blast-radius: 56,481 versus 39,242, 31 percent fewer. Recall was identical and complete in both arms on all three tasks.
Median fresh input tokens, n=3 valid sessions per cell, on the three fully-measured tasks. Recall under each bar pair is the answer-key slot count — the same in both arms, which is what makes the token gap a saving rather than a trade.

What this does not show. Two of the seven tasks were never measured — an external session limit consumed them, and they stay unmeasured rather than being quietly dropped. One repository, one model, one permission environment. No causal isolation of individual tools. The benchmark also found a real defect in our own call graph, which the released engine ships fixed. Full preregistration, results and caveats are in the repository.

Runs where your code is

Local, read-only, and offline by default.

Your source never leaves

There is no upload path in the query loop. No account, no network dependency, no telemetry sent anywhere.

Hostile-repo hardened

Symlinks are never followed, paths are containment-checked, and git runs with hooks, filters and exotic transports disabled.

Derived state is disposable

The index verifies itself against the repository it describes. If integrity cannot be established it is rebuilt, and it says so.

Honest envelope. Validated to roughly 10,000 files, comfortable well below that. Memory is the binding constraint above it. The measured numbers, including where it stops, ship with the package.

Euthynos for teams

The same engine, standing between a pull request and main.

The CLI answers one developer’s questions. This answers the repository’s — on every pull request, with the same determinism. Not open — leave your address and you will hear first.

The first release

  • Merge policy as rules Budgets and thresholds a build can enforce, not a convention people remember.
  • A dependency graph per scan Every scan keeps its graph, so you can see what moved between two commits.
  • A check run on every pull request Zero LLM calls, so the same diff produces the same verdict every time.
  • An evidence export Why a change was allowed or blocked, in a form an auditor can read months later.

Being built after that designed, not shipped

  • Cross-repository blast radius What a change reaches past this checkout — sibling packages in a workspace, your own published packages, typed API clients. One checkout cannot see any of it; a registry of scans can.
  • Schema and ORM impact Which code actually reads a column, before you migrate it — including the raw-SQL job no call graph reaches.
  • Runtime overlay Your own APM data on the same graph: this caller was observed at 400 req/s in production last week. Observation, not permission.
  • Code-to-infrastructure boundary Which manifest defines the environment variable this code reads, across Terraform and Kubernetes.

Every one of these answers the same way the CLI does: it names its own scope. Cross-repo evidence will say which consumers were found and where the search stopped — never “nothing else uses this”, which is a claim no static analysis can make.

Request early access

Four questions. The last two are optional.

One email if and when it opens. Nothing else, ever.

Your address is stored on our own database and is never sold, shared or used to identify you. The local CLI stays free, offline and Apache-2.0 — it does not require any of this.

You’re on the list

Thank you — your request is in. We read every signup, and you will get one email when early access opens. Nothing before that, nothing else, ever.

Nothing to do meanwhile. The command-line engine is already free, offline and Apache-2.0 if you want to start there.

Give your agent something better than a guess.

One command to install, one to register it with your agent. Apache 2.0 licensed.

npm install -g euthynos
claude mcp add euthynos -- euthynos mcp