Skip to content

Developer guide: Shadow graph technical ​

This document provides a deep dive into the architecture, implementation, and mathematical models underpinning the Shadow Graph and the Hybrid Search engine in Vault Intelligence.

1. Architectural overview ​

The Shadow Graph is a dual-engine indexing system designed to combine the strengths of vector search (semantic retrieval) with graph theory (structural relationships).

The dual-engine core ​

  1. Orama (Vector Store): A fast, in-memory search engine providing vector and keyword retrieval.
  2. Graphology (Relationship Engine): A formal graph library for maintaining note connections, calculating centrality, and performing multi-hop traversals.

Edge Typing: Edges are typed (source: 'frontmatter' vs source: 'body') to prioritize structural hierarchy over casual mentions. Frontmatter links (e.g. topics:) are treated as stronger signals during traversal.

Main thread vs. worker ​

To prevent UI jank, all graph and vector operations happen in a Web Worker.

2. Hybrid search pipeline ​

The search pipeline follows a three-stage "Retrieve and Re-rank" architecture.

Stage 1: Candidate retrieval ​

Initial candidates are pulled from Orama using a mixture of Vector Search (semantic) and Keyword Search (exact match). The threshold is kept low at this stage to ensure high recall.

Stage 2: Graph analysis ​

For every candidate in the pool, the engine queries the Graphology instance to extract structural metrics:

  • Centrality: Degree centrality (normalized by graph size).
  • Activation: Neighbor analysis. Does this node connect to other nodes that also matched the query?

Stage 3: GARS re-ranking ​

The final relevance score (GARS) is calculated by combining normalized component scores with user-configurable weights.

$$GARS = (sim \cdot W_{sim}) + (cent \cdot W_{cent}) + (act \cdot W_{act})$$

Where:

  • $sim$: Vector similarity/relevance.
  • $cent$: Node centrality (structural importance).
  • $act$: Activation (connectedness to other hits).

3. Ontology traversal: topic siblings ​

A key innovation in Vault Intelligence is the Topic Sibling traversal. This enables discovery of related notes that are conceptually linked through a shared topic even if they lack direct wikilinks.

The algorithm ​

  1. 1-Hop Discovery: Find direct neighbors of the seed file.
  2. Topic Identification: A node is identified as a "Topic" if:
    • It resides in the configured ontologyPath (e.g. Ontology/).
    • Its in-degree exceeds HUB_MIN_DEGREE (default: 5).
  3. Sibling Expansion: For every identified Topic neighbor, look "backwards" (inbound neighbors) to find other notes linking to it.
  4. Hub Penalty: To avoid noise from massive hubs (e.g. Daily Notes), scores are penalized using a logarithmic decay function based on the topic's degree.

4. Adaptive context assembly (the accordion) ​

The ContextAssembler uses a proprietary Accordion Strategy to pack the maximum amount of relevant information into the LLM's context window without exceeding its limit.

Allocation logic ​

Documents are ranked by GARS and assigned a "Context Mode" based on their position:

ModeRelative ThresholdContent
Full Content>= 90% of topEntire document body is read (capped at 10% context budget).
Snippet>= 70% of top500-character blocks around query matches are extracted.
Structural>= 35% of topHeaders (TOC view) extracted from metadata. Capped at top 10 files.

Precision controls ​

  • Expansion Floor: Neighbor expansion only triggers for seeds with an absolute score >= 0.40.
  • Structural Cap: A hard cap of 10 structural documents prevents metadata bloat.
  • Batch Metadata: Fetches all headers in a single worker call to avoid per-file loop latency.

Sliding budget ​

The budget is distributed using a Soft Limit Ratio (default: 10% per doc). If a high-rank doc is small, the remaining space is carried over to the next document in the list, ensuring efficiency.

5. Persistence and state ​

Serialization bridge ​

Because the graph and index live in the worker, state must be serialized for persistence.

  • Format: MessagePack binary format (.msgpack).
  • Optimization: Numerical arrays (embeddings) are cast to Float32Array before encoding to minimize overhead.
  • Graphology: Uses graph.export() and graph.import().
  • Orama: Uses the native save() and load() functions.

Alias normalization ​

The worker maintains an internal aliasMap synced from the main thread to resolve wikilinks (e.g. [[PF]]) to their canonical paths before traversal or re-indexing.

Incremental synchronization ​

The GraphService registers event listeners for vault changes. Only modified files are re-indexed. On rename or delete, the worker removes the stale entry from both the graph and the vector index to ensure data integrity.


Implementation notes for contributors ​

  • Path Normalization: Always use workerNormalizePath inside the worker to prevent OS-specific path issues.
  • RPC Overhead: Use Comlink.proxy() for passing large data or callbacks across the bridge.
  • Memory Management: The worker index is cleared and rebuilt only if critical config (embedding model/dimension) changes to avoid high CPU spikes.