Content Graph Architecture
Thinking-in-progress on how the vault’s relationship graph should be built, maintained, queried, and published. Captured 2026-03-09 after extended design discussion. See also: [Publishing Requirements](Publishing Requirements.md), [Diagram of Object Relationships](Diagram of Object Relationships.md).
Core principle: vault front matter is the authoritative data
All structural relationships (isIn, partOf, dependsOn) live in note
front matter. Everything else — the published website’s related-items sections,
the agent query index, Obsidian Dataview/Bases views — is derived from that
data. No derived artifact is authoritative; all can be rebuilt from the vault.
Four consumers, four different needs
| Consumer | What it needs | Mechanism |
|---|---|---|
| Quartz / web site | Static markdown it can render; related-items baked into output | Quartz transformer reads front matter at build time, injects relationship sections |
| Agent / automation | Queryable, traversable graph; fast lookups | index.json built from vault front matter; vault files are too slow to query directly |
| Obsidian (authoring) | Dynamic views while editing | Dataview queries or Bases in templates; local only, not published |
| n8n triage workflows | Dependency graph for root-cause analysis | Same index.json; walk dependsOn upward from a failing device |
These are genuinely different problems. Trying to solve all four with one mechanism causes the design to feel intractable.
The build-index approach
A script (build-index.py or equivalent) walks the vault, reads all front
matter, and emits a single index.json containing the full graph:
{
"nodes": {
"50-Devices/Home Network/UDM.md": {
"title": "Unifi Dream Machine (UDM) Pro SE",
"isA": "device",
"isIn": "30-Areas/Duplex/Unit B/Network Shelves.md",
"partOf": ["40-Systems/Home Network/index.md"],
"dependsOn": ["50-Devices/Power/AC Power/UPS/Lab UPS.md"]
},
...
}
}- Vault is the source — index is rebuilt on demand, on commit, or by n8n trigger
- Agents query the index, not raw markdown files
- Quartz transformer can consume the same data at build time
- Front matter link maintenance pain is real but contained to the source; the index is always rebuilt fresh so stale derived data is not a risk
Related-items sections on the published site
Six traversal directions on the existing properties drive the related-items section for any note:
| Direction | Derived from | Example |
|---|---|---|
Up via isIn | note’s own front matter | ”Located in: Network Shelves” |
Down via isIn | inverse — all notes pointing here | ”Contains: UDM, Patch Panel, …” |
Up via partOf | note’s own front matter | ”Part of: Home Network” |
Down via partOf | inverse — all notes pointing here | ”Members: UDM, Fiber Modem, …” |
Out via dependsOn | note’s own front matter | ”Depends on: UPS, Fios” |
In via dependsOn | inverse — all notes pointing here | ”Required by: n8n, Home Assistant, …” |
Not every note has all six. The Quartz transformer should only render sections that have at least one entry.
See [Publishing Requirements](Publishing Requirements.md) for parent trail, child list, sibling, and ordered-member rendering details.
Discovery integration (planned, not started)
Unifi and Home Assistant can be sources of truth for devices they can see:
- Unifi: MAC address, IP, switch port, AP association, hostname
- Home Assistant: every integrated device and its state
Proposed flow: new device appears in Unifi → n8n webhook → create stub note
in 50-Devices/ with known front matter pre-filled (title from hostname,
isA: device, dependsOn from network topology if determinable).
What discovery tools cannot see — physical infrastructure, upstream services,
partOf relationships — still requires human input, but that is a much
smaller surface.
The connections question (open)
Physical connections (ethernet cables, power cords) are not currently modeled. The test for adding a property: would a person troubleshooting or an n8n workflow benefit from knowing this?
Ethernet connections — worth defining. If the UDM goes down, knowing which
devices are on which port is actionable for triage. dependsOn captures the
dependency but not the physical path.
Proposed simple form (to be refined):
connectedTo:
- "[[50-Devices/Home Network/UDM.md]]"Port details can live in the note body rather than front matter for now.
Power connections — not yet. dependsOn: UPS already captures the
meaningful operational dependency. Physical cord tracking adds little until
there is a managed PDU that can act on the information.
What is deferred
The following are parked pending more content being written “the hard way,” which will clarify what hurts most:
- Auto-generating and maintaining related-items sections in note bodies
- Deciding between inline injection vs sidecar files vs Quartz-only rendering
- Breadcrumbs plugin investigation (configured but not yet fully understood)
- Dataview backfill script for existing notes
build-index.pyimplementation- Ordered-member rendering (prev/next for circuits, irrigation zones, etc.)
Open questions
-
Should related-items sections be injected into note bodies (requires maintenance), live in sidecar
.ctx.mdfiles, or only be rendered by Quartz at build time (never touch source files)? -
What triggers index rebuilds — git commit hook, n8n webhook on vault change, or on-demand script?
-
Should
connectedTobe added to the property model now, or wait until there are enough device notes to make the value clear?