Agent-native code intelligence: turn any repo into a queryable code graph over MCP. tree-sitter + SQLite, no embeddings, no API keys.
Cartograph demonstrates strong naming conventions (verb-first: find_, search_, get_, who_, what_, blast_, related_, file_, architecture_, index_) and comprehensive parameter descriptions with type constraints (min/max bounds, enums for filters). Tool descriptions are well-crafted for LLM decision-making, explicitly stating WHEN to use each tool vs. alternatives (e.g., find_symbol vs. search_code). However, output schemas are entirely undocumented, the code returns Markdown strings via views.symbols_table() and similar formatters, but the LLM has no visibility into what fields or structure those Markdown responses contain. Error handling is present but generic (_error() function returns plain text guidance). No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite all tools being read-only. Parameter validation is implicit in type constraints but not validated at runtime with actionable error messages.
Module graph, layering, cycles and hotspots -- computed from imports and the call graph.
Impact analysis: what a change here could break, and which tests to run. Combines the reverse import graph with the reverse call graph, then highlights test files specifically. Recall-first by design (confidence >=0.3): the expensive mistake is a missed impacted test, not an extra one. Call this before editing shared code and after finishing, to pick tests.
What is in this file? Symbols defined, imports, and its place in the call graph.
Locate where a symbol is DEFINED, with its file:line, signature and doc. This is the right first call for "where is X?" -- it is exact and ranked by structural importance, so if a repo has six functions called `run`, the one the codebase actually revolves around comes first. Use `search_code` instead when you only know roughly what the thing does ("the retry logic") rather than what it is called.
Full detail for one symbol: signature, doc, members, callers and callees. Prefer this over reading the whole file: you get the definition plus its immediate graph neighbourhood, which is usually all the context needed to make a safe edit. Set `include_source=true` when you intend to modify it.
Output schemas completely undocumented. All tools return Markdown strings via views.symbols_table() and similar formatters, but LLMs have no visibility into response structure, field names, or data types. This forces LLMs to parse unstructured text and guess at downstream field availability.
No tool annotations despite all tools being read-only. Missing readOnlyHint declarations prevent clients from optimizing caching, retry logic, and safety guarantees. Agents cannot distinguish safe-to-retry tools from destructive ones.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | 2026-07-28+ | v2 |
Summary statistics: files, symbols, edges, languages, and resolution rate.
"What else should I read before touching this?" via the call graph. Runs personalized PageRank seeded on the anchor symbol and treats the call graph as undirected, so it surfaces collaborators a plain caller/callee list misses -- siblings that share a hub, helpers two hops away. This is the structural analogue of semantic search, and it needs no embeddings: proximity in the call graph *is* the relationship.
Full-text search across symbol names, signatures and docstrings (BM25). Use when you know the intent but not the identifier. Results are re-ranked by call-graph importance, so central symbols outrank incidental mentions.
Forward call tree: what this symbol depends on, transitively. Use it to understand an unfamiliar function without reading every file it touches, and to spot the layer a piece of code really sits in.
Reverse call tree: everything that reaches this symbol, transitively. The tool to use before changing a signature, tightening a validation, or deleting anything. Each edge reports the rule that produced it; treat sub-0.5 edges as leads rather than facts.
file_summary and index_stats have weak descriptions (60 and 50 chars respectively). 'What is in this file?' and 'Summary statistics' lack context for when to call them vs. alternatives. Should explain use cases and prerequisites.
Error handling returns generic Markdown text (_error function) without structured guidance. LLMs cannot programmatically determine if an error is retryable, user-fixable, or fatal. IndexNotFoundError guidance is helpful but others are bare exception names.
No runtime input validation with actionable error messages. Type constraints (ge=1, le=100) are declared in Pydantic but validation failures return generic HTTP 400s. LLMs cannot self-correct without explicit constraint feedback.