Skip to main content

Module graph

Module graph 

Source
Expand description

graph — the wiki-link relationship layer.

Wiki-links are curated-relevance edges (the LLM wrote them), so the graph’s job is to assemble the relevant context around a seed, not to be analyzed. All ops are on-demand — there is no maintained graph (a persistent graph is the roadmap engine).

backlinks / forwardlinks are loop ops (O(changed), never O(store)). neighborhood is the high-value context-hydration op. orphans is a SWEEP curation worklist.

Whole-graph analytics (connected components, cycle detection, shortest path, sinks/sources, DOT/JSON export) are deliberately not here — a human studying the graph opens the store in Obsidian; broken-link detection is crate::validate’s job (WIKI_LINK_BROKEN).

§Implementation note — two paths for the incoming-edge scan

The scale contract (SPEC § Tooling, plan: “the interactive loop is O(changed), never O(store)”) is the load-bearing rule here. backlinks is a loop op, so it must not open and read_to_string every content file in the store on each call. It resolves incoming edges by one of two paths, chosen by whether the call is scoped:

  • Unscoped (dbmd graph backlinks <x>, no --type/--in): one embedded-ripgrep pass for the literal [[<target>]] over the tree, via Store::find_links_to (grep + ignore, early-exit per file) — the same scan engine crate::validate’s working-set incoming-linker step uses. A single store traversal with cheap presence-only matching, not N whole-file parses; that is what keeps the unscoped call inside the loop budget. backlinks then filters the raw hits to content files and emits canonical bare targets (its relationship view), where the lower-level Store::find_links_to returns every .md the text appears in.
  • Scoped (--type / --in): the candidate set is enumerated from the relevant type-folder index.jsonl sidecars — one sequential read per type-folder (via crate::query::Query, which sits on Store::read_type_index) — and each candidate is confirmed by a single-file parse. That is what makes --type / --in an I/O scope, not just a result filter: a typed/layer-scoped backlinks reads only the relevant folder(s)’ sidecars and parses only those files.

Why the scoped path confirms by parsing the candidate, not by trusting the sidecar’s links field. A sidecar record’s links is the file’s frontmatter links: list only — it does not capture wiki-links written in the body or inside other typed frontmatter fields (company: [[…]], attendees: [ … ], derived_from: [ … ]). forwardlinks extracts edges from the whole file, so to keep the two directions on the same edge set (an incoming edge to X is exactly: some file whose forwardlinks contains X) the incoming-edge confirmation re-parses each candidate file the same way. The sidecar bounds which files are candidates; the parse decides whether each truly links. The unscoped ripgrep path stays on that same edge set by matching the link text wherever it lives in the file (frontmatter or body). A node’s summary / type likewise read frontmatter directly (the source of truth the sidecar is derived from; never stale).

Structs§

ContextNode
One node reached during a neighborhood hydration: the file, its summary, and how it connects back toward the seed.
ContextSlice
The readable working-set digest neighborhood returns: the seed plus the reached nodes with their summaries and connections. The relationship-axis “turn a seed into context” primitive.

Enums§

Direction
Which edge directions a traversal follows.

Functions§

backlinks
Incoming edges to path: files that wiki-link to it. The blast-radius / dependents primitive before an edit. Store-wide (every layer / every type); see backlinks_filtered for the --type / --in-scoped form.
backlinks_filtered
Incoming edges to path, scoped by the linking file’s type and/or layer — the dbmd graph backlinks --type/--in surface.
forwardlinks
Outgoing edges from path: the wiki-link targets extracted from that single file. Loop-fast; follow the evidence chain.
neighborhood
Context hydration. Bounded BFS from seed over backlinks + forwardlinks out to hops, reading each reached file’s summary + relationship, and returning a readable ContextSlice. Optionally filtered by types and direction. On-demand; no maintained graph. What the agent reaches for to assemble a working set in one call.
orphans
SWEEP. Content files with no incoming AND no outgoing wiki-links — the curation worklist (“ingested but not yet wired into the wiki”). Off the loop. Optionally scoped to a layer.
rewrite_links_to
Write-side. Rewrite every incoming [[old]] wiki-link in text to [[new]], preserving any |display override and emitting the canonical bare target (no .md). The write-side twin of backlinks: where backlinks finds the files carrying an edge to old, this retargets that edge to new inside one file’s contents.