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, viaStore::find_links_to(grep+ignore, early-exit per file) — the same scan enginecrate::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.backlinksthen filters the raw hits to content files and emits canonical bare targets (its relationship view), where the lower-levelStore::find_links_toreturns every.mdthe text appears in. - Scoped (
--type/--in): the candidate set is enumerated from the relevant type-folderindex.jsonlsidecars — one sequential read per type-folder (viacrate::query::Query, which sits onStore::read_type_index) — and each candidate is confirmed by a single-file parse. That is what makes--type/--inan I/O scope, not just a result filter: a typed/layer-scopedbacklinksreads 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§
- Context
Node - One node reached during a
neighborhoodhydration: the file, itssummary, and how it connects back toward the seed. - Context
Slice - The readable working-set digest
neighborhoodreturns: 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); seebacklinks_filteredfor the--type/--in-scoped form. - backlinks_
filtered - Incoming edges to
path, scoped by the linking file’stypeand/or layer — thedbmd graph backlinks --type/--insurface. - 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
seedover backlinks + forwardlinks out tohops, reading each reached file’ssummary+ relationship, and returning a readableContextSlice. Optionally filtered bytypesanddirection. 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 intextto[[new]], preserving any|displayoverride and emitting the canonical bare target (no.md). The write-side twin ofbacklinks: wherebacklinksfinds the files carrying an edge toold, this retargets that edge tonewinside one file’s contents.