Features
A Graph of the Fleet, Not a Grep of It
Lattice parses 16 AVIAN Python codebases with the stdlib ast module — zero third-party parser dependency — into a graph of symbols and their relationships, then serves that graph two ways: as MCP tools an AI coding agent queries for a few hundred tokens instead of tens of thousands, and as a Canvas 2D visualizer that renders architecture as concentric depth rings. The interesting engineering problem is call resolution without a type-inference engine: because every function across the indexed repos is annotated, Lattice reads a receiver's declared type from the source rather than guessing it — and refuses outright rather than fabricate an edge when it can't.
Extraction
Stdlib ast Only — No Tree-sitter, No Jedi
Zero-Dependency Parsing
The Python extractor walks the stdlib
astmodule exclusively — no tree-sitter, no jedi, no third-party parser. It handles every file across all 16 indexed repos with zero parse failures, and a full re-index of the entire fleet completes in well under a minute.Per-File, Pure Extraction
Extraction is strictly per-file with no cross-file work — a file's own imports, base classes, annotations, and call sites, nothing more. That purity is what makes parsing parallelizable and keeps the Swift/Kotlin extractor seam clean for when those languages join Python in scope.
Read-Only By Construction
Lattice never writes to an analyzed repo — no marker files, no
.gitignoreedits, no config injection. A dedicated test asserts this invariant and it is never skipped. The indexer opens source files for reading only.Entry-Point Detection
FastAPI route decorators,
if __name__ == "__main__"blocks, CLI command decorators, MCP tool handlers, and Lambda handler signatures are all auto-detected as runtime entry points, seeding the depth-ring layout and the topological-depth metric.
Resolution
Annotation-Driven, Never Guessed
Three Passes, Cheapest First
Bare calls resolve via lexical scope, then module imports, then builtins.
self.foo()resolves against the enclosing class and its bases. The hard case —x.foo(), the largest single call-site shape across the fleet — resolves by readingx's declared type from a parameter annotation, an explicit local annotation, or a class attribute annotation, then looking upfooon that type.Inferred Local Types
A local assigned from a constructor call (
x = SomeClass(...)) or a call into an already return-annotated function (x = obj.method()) gets a derived type too — taggedinferred, notannotation, so provenance stays honest. Only trusted when the call itself resolves at an exact tier, never chained through another inferred local.The Heuristic Tier Is Timid on Purpose
When nothing else resolves a method name, Lattice checks whether that name is globally unique across the repo. If it is, the edge is recorded at confidence 0.5 so consumers can filter it out. If it isn't unique, the call is left
unresolvedrather than guessed.Never Fabricate An Edge
The governing rule: a confidently wrong call graph is worse than an incomplete one, because an agent acts on what it's told. Every edge carries a
resolutiontag (scope,import,self,annotation,inferred,heuristic,external,unresolved) and a confidence score, so a consuming agent can decide how much to trust it.
Metrics
Depth, Centrality, Blast Radius
Topological Depth
Multi-source BFS from every detected entry point assigns each symbol a depth — entry points at 0, foundational utilities deepest inward. Unreachable code gets no depth at all, which is itself a signal: dormant code with no path from any entry point.
PageRank Centrality
Standard PageRank over the call graph ranks structural hubs. It drives node size in the visualizer and search ranking — a query for a common word surfaces the central orchestrator that owns it, not an obscure helper that merely shares the name.
Blast Radius, in SQL
A recursive CTE walks the call graph backward from any symbol to find everything that transitively depends on it, grouped by hop distance. Because it runs as one Postgres query rather than a round-tripped Python BFS, five-hop blast radius on the most-connected symbol in the largest indexed repo returns in well under half a second.
In/Out Degree
Fan-in and fan-out per symbol are stamped at index time alongside depth and PageRank, giving a cheap, precomputed answer to "how coupled is this" without a live graph traversal.
MCP Integration
Four Tools, Compact By Construction
context(symbol)Signature, docstring, exact file:line, direct callers, direct callees, and structural metrics for one symbol — roughly 350 tokens against the 25,000–35,000 tokens the equivalent multi-file read-and-grep costs by hand.
impact(symbol, max_hops)The recursive-CTE blast radius, exposed directly: run this before editing a symbol to see what could break, grouped by hop distance so an agent can judge whether a change is contained or systemic before touching a single line.
search(query, kind?)Trigram-matched symbol search ranked by PageRank rather than plain string relevance, so the structurally central match sorts first — the orchestrator, not an obscure helper that happens to share the word.
overview(module)A module's public surface and its inbound/outbound dependencies in one call — the fast way to orient in an unfamiliar package before reading a single file.
Never File Bodies
Every MCP response is compact by construction: signatures and
file:linecitations, never full source. If a response ever starts carrying file bodies, that's treated as a defect, not a feature — the agent reads the actual file only when it genuinely needs to, with the exact location Lattice already gave it.
Visualizer
Depth Rings, Not a Force-Directed Hairball
Concentric Depth-Ring Layout
Entry points sit on the outer rim; foundational utilities sit at the centre. Radius is topological depth, angular position clusters by top-level package, and node size scales with PageRank — architecture becomes legible at a glance, and an edge crossing many rings is a layering violation you can literally see.
Blast-Radius Mode
Select any symbol and every dependent recolours by hop distance on a red-to-purple gradient, everything outside the radius dimmed to near-invisible. The shape tells the story: a compact red-orange cluster is a safe change, purple firing across the whole diagram is not.
Canvas 2D at Fleet Scale
Rendered on Canvas rather than SVG or DOM elements — the indexed graph runs to thousands of nodes and tens of thousands of edges, well past what per-element DOM rendering would hold up under while panning and zooming.
Accessibility
Built for Everyone
WCAG 2.1 AA Compliance
4.5:1 contrast for body text, 3:1 for large text and UI components, in both light and dark themes.
Keyboard Navigation
Every interaction reachable via keyboard. Logical tab order, visible focus indicators, Escape-to-dismiss for modals.
Screen Reader Support
VoiceOver, NVDA, and JAWS tested. Semantic HTML, ARIA labels, live regions for dynamic updates.
Reduced Motion
Respects
prefers-reduced-motion. Usable at 200% zoom. Touch targets meet 44x44 minimum.
How It Works
Parse, Resolve, Measure, Serve
Step 1: Parse
The stdlib-ast extractor walks every file in all 16 indexed repos in parallel, per-file and pure — nodes and unresolved call-edge stubs out, nothing else. Content-hash diffing means an unchanged file costs nothing on the next index.
Step 2: Resolve
A global symbol table turns edge stubs into real edges across three cheapest-first passes plus the inferred-local-type pass, tagging every result with exactly how it was derived and how confident that derivation is. Nothing is ever guessed into existence.
Step 3: Measure
Topological depth, PageRank, and in/out degree are computed over the resolved call graph and stamped onto every node — the substrate for both the depth-ring layout and PageRank-ranked search.
Step 4: Serve
Four MCP tools and a REST API read the stored graph and nothing else — no source re-parsing at request time — so an MCP call is a Postgres round-trip, and the visualizer renders the same data the agent just queried.
Technical Specifications
Under the Hood
Backend
- FastAPI (Python 3.12+), SQLAlchemy 2.x + asyncpg, Alembic
- PostgreSQL on the shared supporting-services instance, dedicated
latticedatabase - Extraction: stdlib
astonly — no tree-sitter, no jedi - Metrics: networkx (PageRank, BFS), MIT licensed
Frontend
- React 19 + Vite + TypeScript
- Canvas 2D rendering — depth-ring layout, blast-radius recolouring
- Light and dark mode
- Pan, zoom, hover-highlight, click-to-inspect, package/kind/PageRank filters
MCP Server
- Stdio transport, registered per-session — no daemon to manage separately
- Four tools:
context,impact,search,overview - Reads the database only — zero source parsing at request time
- Every response cites
file:lineso an agent can read source only when it genuinely needs to
Scale & Privacy
- 16 repos indexed, 610K+ lines, zero parse failures across the fleet
- Local-only — no cloud deploy, no external network calls, no telemetry
- No dependency under a non-commercial licence, enforced by a dedicated test
- Every edge auditable:
resolutiontag + confidence score, never a silent guess
Development
100% Built by Claude
Every tool in the Renkara fleet was built by Claude (Anthropic) working alongside a single human supervisor. Every line of code, every test, every deployment: AI-authored with human direction. The leverage factor across the fleet runs in the 20x–50x range, with individual sessions regularly exceeding 100x.
See the daily leverage records for per-task numbers across the full build history.