Skip to content
Conduit

mcp server

alidade

Whole-repository code graph for AI agents, served over MCP. Type-resolved calls for Go, TypeScript, Svelte and Python, joined to .proto, SQL, PXF and Markdown. Built by compilers, with no model in the

belluikit/alidadecommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 29, 2026

alidade

CI Release License: MIT

A code graph of your whole repository, for AI agents, served over MCP.

alidade maps a repository as one graph: code with real types, plus the schema and document layers no single tool sees. An agent asks it who calls a function, what implements an interface, or which code uses a database column, and gets an answer a text search cannot give.

An alidade is the sighting rule on a plane table. You take bearings on several landmarks, and combining them is what produces the map. That is the architecture: alidade performs no analysis of its own. It composes analyses that already exist, and owns the graph they feed.

What it reads

layerread by
Go, type-resolvedcaliper, over the Go type checker
TypeScript, JavaScript, SvelteTypeScript 7's compiler (typescript-go, in process) for declarations and calls; esbuild's resolver for imports
Pythonjedi, in a CPython linked into the binary (pylib)
.protoprotocompile
SQL (PostgreSQL, sqlc)sqlc.yaml and the migrations
.pxfprotowire-go
Markdowngoldmark
goasm templatesgoasm

Generated code joins the layers: a .proto message to its Go and TypeScript types, a SQL query to its generated Go function.

Why alidade

One question can cross layers

A schema, the code generated from it, the code that uses that, and the documents that describe it are one graph. In chameleon, "what depends on the ChainSpec message?" has five kinds of answer, and alidade returns them together:

whatwherehow alidade knows
the messageproto/chameleon/v1/chain.protoread from the .proto
configuration typed as itexamples/simple/chain.pxf, examples/buf/chain.pxfeach file's @type
its generated Go typeproto/chameleon/v1#ChainSpecprotoc-gen-go's own rule
Go code using that typechain#toChainSpec, chain#expandLayers, chain#readEnvironments, chain#Options.normalizeContext, bundler#planLayers, bundler#unionRecipientsthe Go type checker
documents naming itREADME "Chain spec", a CHANGELOG entrya code span naming one declaration

A text search finds the lines that spell ChainSpec. It does not tell the generated type from its uses, or follow the message into the code that only ever names the Go type.

The graph comes from compilers, not from a model

Go is read by the Go type checker, TypeScript by TypeScript's own compiler, .proto by a protobuf compiler, Python by jedi. No model reads your code to build the graph.

  • Building it costs no tokens.
  • Two builds of the same tree are byte-identical. A test fails otherwise.

It is checked against independent ground truth

Each layer is measured against a source that shares no code with it:

layermeasured againstresult
Go callsthe type checker's view of every call expression56,071 of 56,071 found, over 15 repositories; every extra edge explained
Go importsgo list5,667: none missing, none extra
SQLsqlc's own catalog75 of 75 tables, 351 of 351 queries
Python callscalls recorded while two projects' test suites ran10,234 of 10,612, and 1,002 of 1,192

Python is the layer where an answer can be incomplete, and those are its numbers. The repositories are in-house ones and two open-source Python projects. The scripts (scripts/oracle.sh, scripts/pytrace.sh) run on any repository: see Developing alidade.

An answer is about the files as they are now

Before every tool call, the server checks whether a file changed, and rebuilds what did. There is no index to refresh after an edit or a checkout, and none to go stale.

It says what it does not know

  • Every edge states how it was derived, and exclude_inferred drops the heuristic ones.
  • An answer cut to its token budget says what it left out.
  • graph_issues lists the files that did not compile and the edges the graph dropped, and why.
  • graph_stats lists the files it could not read.
  • A Python call jedi has not reached yet is marked as a guess until it has.

Python at the size of a real project

Measured on a project of 1,644 Python files, where type inference over everything takes about 16 minutes:

momentwhat you wait
first answer of a first sessionabout 25 seconds, with unresolved calls marked as guesses while inference continues behind
after a commit that edits filesunder 7 seconds until everything is resolved again: only the files the edit can affect are inferred again
a new session, nothing changedunder 2 seconds: it starts from the answers the last session kept

One binary, and nothing leaves the machine

No Node, no Python and no database to install: the compilers and interpreters it needs are linked in. It talks to the agent that started it over stdio, and opens no port.

Installing

With Homebrew:

brew install belluikit/tap/alidade

Or download a binary for macOS or Linux, arm64 or amd64, from the releases.

To build from source, see Building alidade.

Quick start

Register alidade with Claude Code, once:

alidade setup

Then open any repository and ask a question about how its code relates. The graph is built on the first question, in a few seconds for a repository of a few hundred packages, and kept current as files change.

To make the agent use alidade and not grep in that repository:

alidade setup -enforce

For any other MCP client, the configuration is one command, alidade serve -root /path/to/repo. Using alidade has the details, the flags, and how to turn enforcement off again.

The tools

toolfor
subgraph_for_questionthe neighbourhood of what a question names, across layers
find_nodesan ID from a name: Total, Workspace.ReferencesFor, app.users
neighborswhat is within N hops of a node: its callers, its callees, its implementers
shortest_pathhow two nodes connect
get_nodeone node with its position and its edge counts
search_texttext the graph does not hold, such as a string literal or a log message, each hit with the declaration holding it
graph_statswhat the graph holds, by layer and by how each edge was derived
graph_issueswhat the graph left out, and why
rebuildbuild again now. Rarely needed

Every tool that returns a list keeps to a token budget, and says what it cut. Using alidade explains each one and what the edges mean.

Measured against grep and graphify

47 questions about who calls what, over four public repositories, each asked three times of the same model. Nobody picked the questions: a rule draws them from the Go type checker's calls, and from the calls recorded while a Python test suite ran (#3).

an agent withcorrectcost per correct answermedian time
alidade and Read, no grep138 of 141$0.0196.9 s
Read and Grep137 of 141$0.0367.5 s
graphify as its installer sets it up, with Read and Grep137 of 141$0.0388.9 s
graphify's MCP tools and Read, no grep108 of 141$0.0657.6 s

Accuracy is a tie between alidade, grep, and graphify as installed.

alidade costs about half as much per correct answer. The gap is widest for the callers of a method whose name several types share, where a text search returns every one of them:

12 such questions, three times eachcorrectcost per correct answer
alidade33 of 36$0.015
grep32 of 36$0.054

Where it makes no difference: a function named uniquely enough that grep's matches are its uses. All three practical setups answered those 60 of 60, within a cent of each other.

What this does not measure

  • Only call-graph questions. There are no text, documentation or schema-to-code questions, because no oracle generates those yet.
  • Nothing graphify does beyond calls. graphify reads dozens of languages through tree-sitter where alidade reads four through their compilers, and it adds documents, images and community structure that alidade has no counterpart for. The fourth row is its graph tools with no text search beside them, which is not how it is meant to be run.
  • Python answers are the calls a test suite made. A call no test made is in no answer.
  • One model, one harness, ours. graphify publishes its own benchmark; its code questions are not published, so we could not run them. If we have set graphify up wrongly, please open an issue.

The question sets are in internal/bench/testdata/gen-*.pxf, and scripts/bench.sh runs them: see Developing alidade.

Status

Early. The architecture is settled and recorded in the decisions below, and every layer in the table above is in. Open work is in the issues.

A number such as #206 in the code, the ADRs or the changelog, written before v0.12.0, refers to the tracker alidade had before it was published. That tracker is not public. The changelog and the ADRs carry the measurements themselves.

One limit to know: a file whose path holds whitespace or # gets no node, and is listed as skipped. See Limits.

Documentation

Using alidadeconnecting an agent, flags, how the graph stays current, the tools, what the edges mean, limits
Building alidadebuilding from source, the build tags, compilers
Developing alidadethe checks beyond the fixtures, the oracles, releases
CONTRIBUTING.mdwhat a pull request needs
SECURITY.mdreporting a vulnerability, and what alidade does with a repository it reads
CHANGELOG.mdwhat changed, with the measurements

Decisions

Read these before contributing. They answer most "why is it like this" questions, and each carries the measurement it rests on.

ADR
000alidade composes analyses, it does not perform them
001one binary, layer adapters over a shared graph
002node identity is declaration-anchored, never positional
003six formats and Python, and what is deliberately excluded
004generated code is in the graph, identified
005built on demand; the graph is never persisted
006every edge states how it was derived
007TypeScript and Svelte, joined to .proto through protoc-gen-es
008Python: declarations, imports and calls through jedi in an embedded CPython

License

MIT. See LICENSE. A release binary also carries other projects' code, each under its own license: THIRD_PARTY_NOTICES.txt lists them in full.

↑↓ navigate openesc close