Crate: index. The index turns files and rows into a graph by deriving what sources don’t know: symbols, links, outlines, embeddings, stack frames. It is exposed as IndexSource, so its output is just more nodes and edges.
As built (2026-10-01)
- Extractors: wiki-links (markdown) and tree-sitter symbols for Rust; Julia and Python extractors exist but never run because
walk::wants_textonly fetches markdown and Rust (issue #16). No headings/front matter nodes, no imports, no calls/references (spec 022).- Parsing is native tree-sitter through
arborium(shared with the Rust code editor, P-113) — not.wasmgrammars; the index runs on desktop and the server, and the web/phone query the server’s.- Storage is memory: the graph, BM25 postings (hand-written,
search.rs) and embeddings (brute-force cosine, reciprocal-rank fusion) are rebuilt on every open. No sqlite/duckdb store, no tantivy, no usearch, norecoco. A persisted index is part of Internal State.- LSP as a second extractor and the
precisionfield are not built.- Stack traces live in their own crate,
moonkale-trace(TraceSource), not inindex::trace.
flowchart LR EV[SourceEvent] --> P[pipeline: debounce, prioritise visible] P --> PA[parse: tree-sitter wasm grammars] PA --> X1[Symbols] PA --> X2[WikiLinks] PA --> X3[Headings / Frontmatter] P --> X4[Imports] P --> X5[Embeddings via llm::embed] LSP[lsp::graph] --> ST X1 & X2 & X3 & X4 & X5 --> ST[(store: sqlite/duckdb + tantivy + usearch)] ST --> IS[IndexSource → GraphView]
Decisions
- tree-sitter grammars as
.wasm— one artefact for desktop, web and mobile; contributed by language extensions (Contribution Points). - Two symbol extractors: tree-sitter (fast, always available, approximate) and LSP (precise, needs a server). Derived edges carry
precision; views prefer LSP when both exist. - Incremental by node: a change re-runs extractors for that node only and re-links only its edges. Priority goes to nodes that are visible in some editor.
- Storage is native/server:
tantivy+usearchdon’t target the browser; the web build queries the server’s index. Parsing still runs client-side for highlighting. recoco(Rust-only CocoIndex fork) is a candidate for the pipeline layer; evaluate before hand-rolling scheduling.
Stack traces and ASTs
index::trace parses rustc/Julia/Go/Python trace formats into Frame nodes with Calls edges, linked to Symbol nodes. A panic in the Terminal becomes a clickable subgraph in the Graph View with a hierarchical layout. Function ASTs are the tree-sitter tree exposed as a GraphView (nodes = syntax nodes) — free once parsing exists.
Embeddings and RAG
See LLM and RAG. Chunking is per symbol / heading / row; vectors are stored locally (usearch) or in the source when it has VECTOR (pgvector, HelixDB). Hybrid search = BM25 (tantivy) ∪ vector, fused.