Cartographer developer setup
Cartographer builds an incremental tree-sitter symbol index of a repo and serves it to your agent as tools — one call answers “where is X used / what do I open to change it” instead of a grep-and-read loop. Most queries are zero-token, and the org’s shared graph is versioned like git.
api./app./mcp. endpoints was decommissioned during the AnchorageLabs → Legios migration, and that domain is no longer ours — so this guide no longer prints an installer, a sign-in, or a connector URL pointing at it. Everything below runs from a clone of the private repo: the graph is shared over git, and MCP runs locally. If a hosted service is ever rebuilt, it will be on a Legios domain and this page will say so.git clone [email protected]:legiosai/cartographer.git
cd cartographer && corepack enable
pnpm install --frozen-lockfile && pnpm buildMeasured on a real repo: a “where/impact” question costs ~103k tokens via grep-and-read vs ~300 via one Cartographer call.
Step 01
Build the CLI from the repo
Prerequisites: Node 22+ and repo access. Cartographer is private and there is no published package or installer — during the private beta the only way in is a clone. The parsers are WASM run by your Node; nothing native gets compiled.
git clone [email protected]:legiosai/cartographer.git
cd cartographer
corepack enable # pnpm 9.15.9, pinned in package.json
pnpm install --frozen-lockfile
pnpm buildThat leaves the CLI at dist/cli/index.js. Put it on your PATH under the name the rest of this guide uses, or call it by path:
pnpm link --global # -> `cartographer` on PATH
# or, without touching PATH:
node dist/cli/index.js --helpcurl … | sh and irm … | iex installers served from a hosted API. That host was decommissioned and its domain released — the commands are gone rather than left broken, because a released domain can be re-registered and start answering.cartographer --help # verify the buildStep 02
Authenticate
There is no Legios API token. It authenticated the hosted orchestrator, and there is no hosted orchestrator. Two credentials replace it, and you already have both:
- 1.Your GitHub access — the shared graph rides on git (a branch in the repo, not a server), so whoever can clone the repo can
pullandpushit. Nothing extra to configure. - 2.A secret you pick — the local MCP server refuses to start without one, so an agent on your machine cannot talk to it by accident:
export CARTOGRAPHER_MCP_DEV_TOKEN=pick-a-secret
# Windows PowerShell: $env:CARTOGRAPHER_MCP_DEV_TOKEN = "pick-a-secret"Step 03
Pull the shared graph before you start
cd <your-repo>
cartographer pull # org's latest graph for this repo → local index
cartographer status # three axes: your tree / your index / the graph branchstatus tells you where you stand against the org graph: FRESH (in sync), AHEAD (you have unpushed structure), BEHIND (pull), DIVERGED (pull, re-index, push). Working on a repo you haven’t cloned? Pull it anyway:
cartographer pull --out ~/graphs/aleph --repo your-org/aleph
cartographer impact getUser ~/graphs/aleph --shared # query with NO source tree(--shared serves the pulled snapshot as-is — a normal query would rescan the empty dir and prune it.)
Step 04
Index and query locally
cartographer init # first time in a repo: facts + symbol index
cartographer watch # keep the index current while you edit
cartographer impact startRun # blast radius: defs, refs, dependents, tests
cartographer refs startRun # definitions + every reference
cartographer tests-for src/store.ts # which tests cover this file
cartographer log # org graph history: who pushed what, when
cartographer graph-diff <idA> <idB> # structural delta between two snapshotsEvery query delta-refreshes the index first, so results always reflect your working tree. The index is a gitignored SQLite file (.cartographer/index/symbols.db) — nothing leaves your machine until you push.
Step 05
Push after you change code
cartographer push # snapshot your index → org graph `latest`Push is safe by default: it’s an immutable snapshot plus a compare-and-swap ref advance. If a teammate (or the executor) pushed since you last synced, you get a 409 naming the current head — never a silent overwrite:
push rejected: your-org/x latest advanced to g8c1e… (commit 4fa1b2c9, by …)
fix: cartographer pull # then re-index and push
or: cartographer push --force-with-lease=g8c1e…Re-pushing identical content is a no-op (“up to date”, zero bytes uploaded).
Step 06
Install the agent plugins (MCP)
One server, on your machine:
- Local MCP — the installed CLI serves your checkout with the full 10-tool set (
repo_map,find_references,impact,locate_change,tests_for,symbol_outline,repo_facts,repo_context,context_for_task,graph_status). Start it with:
CARTOGRAPHER_MCP_DEV_TOKEN=pick-a-secret cartographer mcp --port 3100
# your agent then sends: Authorization: Bearer pick-a-secretBelow: exact install per agent. ${CARTOGRAPHER_MCP_DEV_TOKEN} must be exported in the environment the agent starts from, and the server has to be running — an agent pointed at a port with nothing behind it fails at call time, not at startup.
Claude Code
Create (or extend) .mcp.json at the repo root — or ~/.claude.json for all projects:
{
"mcpServers": {
"cartographer": {
"type": "http",
"url": "http://localhost:3100/mcp",
"headers": { "Authorization": "Bearer ${CARTOGRAPHER_MCP_DEV_TOKEN}" }
}
}
}claude.ai (web)
Not available. A custom connector needs a URL the browser can reach, and the local server listens on localhost. Use Claude Code instead, which runs on the same machine as the server.
Cursor
~/.cursor/mcp.json (global) or .cursor/mcp.json (per repo):
{
"mcpServers": {
"cartographer": {
"url": "http://localhost:3100/mcp",
"headers": { "Authorization": "Bearer ${CARTOGRAPHER_MCP_DEV_TOKEN}" }
}
}
}Codex
~/.codex/config.toml — newer Codex speaks HTTP MCP directly:
[mcp_servers.cartographer]
url = "http://localhost:3100/mcp"
http_headers = { Authorization = "Bearer ${CARTOGRAPHER_MCP_DEV_TOKEN}" }Gemini CLI
~/.gemini/settings.json:
{
"mcpServers": {
"cartographer": {
"httpUrl": "http://localhost:3100/mcp",
"headers": { "Authorization": "Bearer ${CARTOGRAPHER_MCP_DEV_TOKEN}" }
}
}
}GitHub Copilot (VS Code)
.vscode/mcp.json in the workspace (the inputs entry prompts once for the token and stores it outside the repo — never hard-code it here):
{
"inputs": [
{ "type": "promptString", "id": "legios-token",
"description": "Legios client token", "password": true }
],
"servers": {
"cartographer": {
"type": "http",
"url": "http://localhost:3100/mcp",
"headers": { "Authorization": "Bearer ${input:legios-token}" }
}
}
}OpenCode
opencode.json (repo) or ~/.config/opencode/opencode.json:
{
"mcp": {
"cartographer": {
"type": "remote",
"url": "http://localhost:3100/mcp",
"enabled": true,
"headers": { "Authorization": "Bearer ${CARTOGRAPHER_MCP_DEV_TOKEN}" }
}
}
}Any stdio-only agent (fallback)
Bridge stdio ↔ HTTP with mcp-remote:
{
"mcpServers": {
"cartographer": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:3100/mcp",
"--header", "Authorization: Bearer ${CARTOGRAPHER_MCP_DEV_TOKEN}"]
}
}
}Support matrix
| Agent / editor | Native HTTP MCP | Config file | Token |
|---|---|---|---|
| Claude Code | Yes | .mcp.json | CARTOGRAPHER_MCP_DEV_TOKEN |
| claude.ai (web) | no (needs a public URL) | — | — |
| Cursor | Yes | ~/.cursor/mcp.json | CARTOGRAPHER_MCP_DEV_TOKEN |
| Codex | version-dependent | ~/.codex/config.toml | CARTOGRAPHER_MCP_DEV_TOKEN |
| Gemini CLI | yes (httpUrl) | ~/.gemini/settings.json | CARTOGRAPHER_MCP_DEV_TOKEN |
| GitHub Copilot (VS Code) | Yes | .vscode/mcp.json | prompted input |
| OpenCode | yes (remote) | opencode.json | CARTOGRAPHER_MCP_DEV_TOKEN |
| Anything stdio-only | via mcp-remote | agent-specific | same |
graph_lookup for <a symbol you know> in <owner/repo> and report the graphId and commit sha the answer came from.” A wired setup names a graph.graphId (g + 32 hex) and a commit; a broken one falls back to grep.Step 07
Logbook — teach it once, every agent knows it
Repo knowledge usually gets re-taught to every agent separately. Logbook is the shared, reviewed alternative: any agent proposes an observation (“this boot command works”, “this test is flaky”), a human promotes it — exactly like a pull request — and logbook compile renders accepted canon into the context files agents actually read (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md, GEMINI.md, .cursor/rules/logbook.mdc):
cartographer observe cmd:boot "make dev boots api+web on :3001" --kind=boot-command
cartographer observations --accept=o0230bc1fcd72 --by=<reviewer>
cartographer logbook compile # accepted canon -> every agent's context fileAgents connected over MCP propose without shelling out (logbook_propose / logbook_list); provenance comes from the client’s identity (set CARTOGRAPHER_AGENT=<agent-name> once), never from tool arguments — and promotion is never exposed over MCP: review stays a human act on the committed .cartographer/observations.ndjson diff. A GitHub Action (legiosai/cartographer/action@v0) fails PRs whose compiled blocks are stale and opens an auto-PR with the recompile after merges. Full spec: docs/logbook.md.
Step 08
One-command verification
cartographer status --jsonHealthy output has "fresh": true (tree vs index) and a "remote": { "freshness": "fresh" | "ahead" | … } block (index vs org graph). If the remote block is missing, your token isn’t exported.
Step 09
Give your agents the Legios Skill
Installing the plugin gives agents the tools; the skill makes them use the graph instead of grepping. Paste the contents of legios-agent-skill.md into each agent’s instructions:
| Agent | Where to paste |
|---|---|
| Claude Code / Codex / OpenCode | CLAUDE.md / AGENTS.md at the repo root |
| Cursor | .cursor/rules |
| Gemini CLI | GEMINI.md |
| GitHub Copilot | .github/copilot-instructions.md |
| Reviewers / custom prompts | the reviewer system prompt |
The skill is Cartographer-scoped: sync-before-work, graph-before-grep tool selection, mandatory impact / tests_for before changing public symbols, 409/lease recovery, version-stamped answers, and honesty/fallback rules.
Step 10
Bring your own LLM (optional)
Core queries are zero-token. Two optional commands call a model: cartographer narrate (plain-language repo summary) and cartographer map --llm (architecture claims). Configure your own key:
export LEGIOS_LLM_PROVIDER=anthropic # anthropic · openai · openai-compatible · bedrock
export LEGIOS_LLM_API_KEY=sk-ant-... # your own key — BYO, never shared
export LEGIOS_LLM_MODEL=claude-sonnet-4-6Step 11
Cheat sheet & troubleshooting
Daily: pull → work (impact / refs / tests-for, agent tools) → push. Keep cartographer watch running during long sessions.
| Symptom | Fix |
|---|---|
| 401 from the local MCP | The agent's CARTOGRAPHER_MCP_DEV_TOKEN doesn't match the one the server started with. |
| MCP tools missing / connection refused | The server isn't running: cartographer mcp --port 3100 in another terminal. |
| Push rejected with 409 | Someone pushed first — cartographer pull, re-index, push (or --force-with-lease=<head>). |
| Empty results after pull | Add --shared (a tree-less snapshot must not be rescanned). |
| Stale local index | cartographer refresh |
| cartographer: command not found | pnpm link --global from the clone, or call node dist/cli/index.js directly. |
| pnpm: command not found | corepack enable (pnpm 9.15.9 is pinned in package.json). |
| graph empty for a repo | That repo's graph hasn't been pushed yet — cartographer log --repo owner/name shows history. |
docs/integrations/. Questions → #cartographer.