Synthesis of a day of research into how to get code-level and concept-level knowledge graphs that link together, are traversable by Claude Code, and handle updates — plus whether Obsidian is still the right tool. Verdict: stay on Obsidian, keep markdown as the source of truth, derive two disposable graphs, and build one reconciler. Backed by four dated surveys: code-graph-survey-2026-09-07, memory-graph-survey-2026-09-07, pkm-survey-2026-09-07, ruflo-evaluation-2026-09-07.
For Agents
Read this before proposing anything graph-shaped for this vault or for ai-project-brain. Five facts that older notes and older blog posts get wrong:
- claude-mem has been disabled since 2026-03-15. Installed at v10.5.2 but absent from
enabledPlugins. Its 1326 observations are all from March, 60 pending messages arefailed, and its configured model isclaude-sonnet-4-5. Do not treat it as a live memory store. Do not read from it.- The documenter hook is orphaned and inert.
~/.claude/hooks/obsidian-documenter-trigger.shis referenced only in claudeconf, not in live settings, and itsCOUNTER_FILEis keyed on$$, so the threshold can never fire. Documentation reaches this vault only through model compliance with CLAUDE.md, never automatically.- Kuzu is archived (2025-10-10, Apple acquisition). Use LadybugDB if an embedded graph database is ever needed. Graphiti deprecated its embedded Kuzu backend as a result. The architecture below needs no graph database at all.
- mem0 removed graph memory from open source in v3 (April 2026).
- ruflo is rejected for this purpose. No code parser, no node table, duplicate facts accumulate forever. See ruflo-evaluation-2026-09-07. Its
initappends to the global~/.claude/CLAUDE.mdandcleanupnever reverses that.The one thing worth building is the reconciler — a job that resolves note
code_refsagainst a current code index and flipsstatus: staleon misses. Nothing off the shelf does this for this vault’s conventions.
Question and method
How to get code-level and concept-level knowledge graphs that link together, are traversable by Claude Code, handle updates, and whether Obsidian is still the right tool. Added mid-research: offload Claude Code to telep-mainframe; evaluate ruflo.
Method: two read-only audits (vault, knowledge stack), one probe of prior art (ai-project-brain, graphtest), four web surveys (code graphs, concept and temporal graph memory, PKM tools, ruflo), one Claude Code docs pass on remote operation. All star counts and dates verified on 2026-09-07.
Verdict
- Stay on Obsidian. No alternative offers typed edges, plain text, and an agent API together. The gap is a machine-readable layer, not the app.
- Architecture: markdown is the source of truth. Two derived, disposable graphs (concept index, code index) joined by one anchor (structured code references in note frontmatter).
- Update handling is a reconciliation job, not a database feature. Resolve every note’s code anchors against the current code index and flip
status: staleon misses. Nothing off the shelf does this for the vault’s conventions; it is the one thing worth building. - Move Claude Code’s home to telep-mainframe. It collapses the cross-Mac state problem (settings, auto-memory, transcripts, hooks, indexes) into one machine that already hosts telep-kb and alexandria.
- Skip ruflo. Stop building a graph database app; narrow ai-project-brain to the reconciler or drop it.
What exists today
Vault (~/levandor_obsidian)
| Measure | Value |
|---|---|
| Notes / project folders | 1051 / 44 |
| Wikilinks | 16,788 (598 bare heading refs) |
| Notes with frontmatter | 96.5% |
| Typed link fields, vault-wide | 21 (related 9, repo 8, parent 3, superseded_by 1) |
| Code identifiers in prose | 43,707 backticked, 5,116 paths, 2,729 file:LINE refs (2,617 unqualified) |
| Files with exactly one commit | 606 of 1079 |
Notes with updated: / status/outdated | 95 / 5 |
| Near-duplicate title pairs (excluding handovers) | 51 |
| Dangling link targets | 103 |
| Name collisions | [[LOG]] x158 and [[TOPICS]] x161 against 43 files each; [[vuer_oss]] x189 against 2 |
| Query plugins | none (Dataview, Breadcrumbs, Juggl absent; Bases on with 0 .base files) |
| Sync | git only via obsidian-git; three author identities; pull --rebase failing on 19 modified + 6 untracked paths at audit time |
| Data loss | auto-backup commit 93aa1d7 (2026-08-31 03:33) deleted projects/alexandria/ (5 notes, ~3000 lines); recoverable from 93aa1d7^ |
Spot-check of six old file:LINE references: four hold, one line drifted to properties: {, one file (vuer_cv/server/appcache.py) is gone.
Documenter compliance: tags 1016/1051, ## Related 714/1051, > [!info] For Agents 606/1051, project/ tag missing on 295 of 999 project notes. The most-violated rule is search-before-create (plan/design/complete triads, dated forks).
Knowledge stack
| System | State on 2026-09-07 |
|---|---|
| Obsidian vault | the only live cross-machine store; written by obsidian-documenter on model compliance, no hook |
Auto-memory (~/.claude/projects/*/memory) | live, per-project and per-machine; 30 project dirs; invisible across repos |
| claude-mem | dead since 2026-03-15: installed v10.5.2, not in enabledPlugins, 1326 observations all March, 60 pending messages failed, configured model claude-sonnet-4-5 |
Documenter hook (~/.claude/hooks/obsidian-documenter-trigger.sh) | orphaned (referenced only in claudeconf, not live settings) and inert (COUNTER_FILE keyed on $$, threshold can never fire) |
~/.claude/settings.json | real file, drifted from dotfiles (15 keys vs 6); only CLAUDE.md and RTK.md are symlinked |
AgentOps .agents/ | ~90 scaffolded dirs, one with content (railscale); ao reports false in environment.json |
| telep-kb MCP | Qdrant collections manuals (hybrid) and notes (vault, semantic only) on telep-mainframe; re-embeds on note content hash; blind to code edits; fail-closed on bad YAML silently drops project units |
| Transcripts | 1175 JSONL files, 933 MB, unindexed |
| Repos | 43 (Rust-heavy), 4 with CLAUDE.md, none with ADRs |
The core gap
Only one file-to-knowledge edge exists in the whole stack (claude-mem
files_modified), and it is inert data in a dead database. A rename invalidates zero notes anywhere.
Prior art
- ai-project-brain (created 2026-09-07,
/Volumes/bandi/coding): workspace scaffold on grafeo 0.5.42 (embedded, GQL, vector/text/hybrid indexes, CDC, file persistence). Does not compile (Pathfield, untyped field inrepo.rs). No schema, no ingest, no CLI. Nested.gitdirs fromcargo new. Its vault note says “there isn’t any architecture yet”. - graphtest (
graphanah, paused 2026-03-10): rustc_driver HIR walker with typeck-resolved references (qpath_res,type_dependent_def_id). Real name resolution, Rust only, nightly-pinned, no incremental mode, containment-only edges, TSV output. Left mid-session. Superseded byrust-analyzer scip, which gives stable symbols without a nightly pin. - alexandria (10 crates, ort + tokenizers + qdrant-client, deployed on telep-mainframe) and dionysus: vector and full-text systems. Local embedding infrastructure already exists on the server.
Landscape
What changed and invalidates older advice: Kuzu archived 2025-10-10 (Apple acquisition; maintained fork is LadybugDB). mem0 removed graph memory from open source in v3 (April 2026). Graphiti deprecated its embedded Kuzu backend. SCIP moved to the neutral scip-code org. GitHub stack-graphs archived. Sourcegraph Cody Free/Pro killed; no self-hostable OSS Sourcegraph. CodeQL CLI licence bars private repos. GitNexus is PolyForm Noncommercial.
Concept layer
Full detail in memory-graph-survey-2026-09-07 and pkm-survey-2026-09-07.
| Tool | Fit | Notes |
|---|---|---|
| Basic Memory (3,878 stars, AGPL, v0.23.2) | adopt | markdown is truth, SQLite disposable; ## Relations - type [[Target]] typed edges; MCP + bm tool CLI + HTTP; official Obsidian integration and Claude Code hooks; no temporal model; pre-1.0, syntax broke once at v0.21.0 |
| Obsidian CLI 1.12 | use in hooks | links, backlinks, unresolved, orphans, deadends, base:query format=json; needs the app running; exit code always 0, parse stdout |
| Bases | use for views | one-hop filters over properties and links, JSON via CLI; no joins, no traversal |
Breadcrumbs v4.15 (now michaelpporter/breadcrumbs) | optional | human-facing typed navigation over the same frontmatter |
| Graphiti (30,657 stars) | later, if ever | only true bi-temporal model (valid_at/invalid_at); needs FalkorDB or Neo4j and several LLM calls per write; extractor ignores reference_time on backfill (issue #1489) |
| trace-mcp (169 stars, MIT, single maintainer) | try, base tier only | vault + code in one SQLite graph; decisions with valid_from/valid_until bound to path::Symbol#kind; decision-verification returns ok, symbol_missing, code_changed; mine_sessions over transcripts with zero LLM calls; Rust edges are essentially only imports, trait-impl edge is a no-op, method ids collide across trait impls; file moves not handled; avoid max tier (patches Claude Code’s system prompt) |
| Dataview | avoid | stale since 2025-11-17; Bases cannot read inline fields |
| claude-mem | drop | a flat session log with LLM compression per session, not a graph; known token and RAM blowups |
Code layer
Full detail in code-graph-survey-2026-09-07.
| Tool | Fit | Notes |
|---|---|---|
| Serena (28,931 stars, MIT) | adopt now | LSP live (rust-analyzer, typescript-language-server, Pyright); no index to keep fresh; find_symbol, find_referencing_symbols; name path is file-scoped; issue #1556: hardcoded heavy rust-analyzer options, 40 GB processes on big Rust workspaces |
| codebase-memory-mcp (42,518 stars, MIT, C) | adopt when cross-repo memory is wanted | single binary, SQLite, read-only openCypher subset with explicit errors; TESTS and FILE_CHANGES_WITH edges; ids <project>.<path>.<name>; commits .codebase-memory/graph.db.zst with merge=ours so the graph travels through git; Rust in its “Good 75-89%” tier; 75 KB README, writes agent config files |
| SCIP to SQLite | build-it-yourself option | rust-analyzer scip . then scip expt-convert; Rust symbols encode crate and module path, so they survive line churn and file moves; rust-analyzer’s SCIP is “pretty limited” per maintainers; scip-typescript and scip-python quiet since late 2025 |
| code-graph-rag (5,055 stars, MIT) | later, on the mainframe | best-engineered: published schema, re-index p50 194 ms, only tool with rename detection (symbols.renamed, dangling_callers); needs Memgraph + Qdrant in Docker; Cypher you can MERGE note nodes into |
| Graphify (115,470 stars) | steal the idea only | wikilinks become edges, exports an Obsidian vault; untyped nodes, graph.json, deleted nodes linger |
| GitNexus, CodeQL, Joern, Potpie, CodeGraphContext, Aider repo-map, Nuanced, FalkorDB code-graph | ruled out | licence, no Rust, parsers deleted, line-keyed ids, dormant, or archived |
ruflo (renamed claude-flow, 71k stars)
Skip. The graph is one graph_edges SQLite table with no node table and bare TEXT ids. No code parser anywhere; extraction is Claude reading files and writing prose. Every insert mints a new UUID then INSERT OR IGNORE with no unique constraint, so duplicate facts accumulate forever; last_reinforced is never updated. ruflo-knowledge-graph, ruflo-rag-memory, ruflo-ruvector, ruflo-agentdb are markdown prompt packs with zero code. Default search is a table scan; real HNSW “not scheduled” (issue #2922). init installs hooks on nine events, spawns a daemon, and appends to global ~/.claude/CLAUDE.md; cleanup never reverses the global edit. ruvector’s Cypher executor returns an empty vector by design. Worth borrowing: the 15-line k-hop recursive CTE shape if the index lands on SQLite. Full evidence in ruflo-evaluation-2026-09-07.
Recommended architecture
Markdown as truth. Two derived graphs, one anchor. Everything below is additive to the current vault and reversible.
1. Note conventions (the concept graph)
---
title: Queue drain timeout fix
type: decision # decision | architecture | debugging | runbook | reference | index
project: polymarket-fetch
status: active # draft | active | stale | deprecated | superseded | archived
date: 2026-09-07
updated: 2026-09-07
verified: 2026-09-07 # last date code_refs resolved cleanly
supersedes: "[[2026-06-01 queue backpressure design]]"
superseded_by:
amends:
code_refs:
- repo: polymarket_fetch
path: crates/engine/src/queue.rs
symbol: engine::queue::Queue::drain
tags: [project/polymarket-fetch, type/decision]
---
## Relations
- depends_on [[Tokio runtime notes]]
- implements [[Queue backpressure design]]Rules:
- A fixed relation vocabulary:
depends_on,implements,supersedes,superseded_by,amends,relates_to,caused_by,fixed_by. - Never edit a decision to reverse it. Write the successor, set
supersedes, flip the old note’sstatus. - Revise a living note in place and bump
updated. Do not fork dated copies. deprecatedmeans no replacement;supersedednames one.- No Dataview inline fields.
- Rename
LOG.mdandTOPICS.mdto project-scoped names through Obsidian so links rewrite. This kills the[[LOG]]x158 and[[TOPICS]]x161 collisions. - One tag form per project (
project/x; drop the flat duplicates).
Index: Basic Memory pointed at the vault gives the typed-edge index, build_context traversal, and MCP for free. Fallback if it misbehaves: a 50-line parser over frontmatter and ## Relations into SQLite.
2. Code graph (derived, disposable, per machine)
Now: Serena as the always-correct symbol layer. When cross-repo memory matters: codebase-memory-mcp per repo, artifact committed. If note rot needs automatic rename detection: code-graph-rag in Docker on telep-mainframe, both Macs pointing at it.
Design rule
Do not persist symbol identity in notes beyond the anchor. Re-derive the code graph. It is disposable by design; only the anchor is durable.
3. The anchor and the reconciler (update handling)
code_refs replaces bare lib.rs:176. Each ref is repo + path + qualified symbol; store the SCIP string when an indexer emits one. The reconciler runs on the server (SessionEnd hook or systemd timer):
- Resolve each
code_refsentry against the current index (SCIP SQLite, codebase-memory-mcp SQLite, or Serenafind_symbol). - Missing symbol gives
status: staleplus asymbol_missingcallout. Symbol body hash changed sinceverifiedgivesstatus: stalepluscode_changed. Resolved setsverified: today. - Run
obsidian unresolved,orphans,deadendsand write one hygiene note. - A
Stale notes.baseview (status == stale) is the review queue.
This is 150 to 300 lines. It is the correct scope for ai-project-brain if it continues; grafeo is unnecessary for it, SQLite suffices. trace-mcp’s decision-verification does the same three verdicts for its own decision table and can be trialled first.
4. Session capture
Disable claude-mem for good. Transcripts are already on disk; mine them with trace-mcp mine_sessions (regex, zero LLM) or Basic Memory’s Claude Code hooks. Keep obsidian-documenter as the deliberate write path, with search-before-create enforced by giving it Basic Memory search_notes and the revise-or-supersede rule.
Offloading Claude Code to telep-mainframe
Recommended topology from current docs: install Claude Code on the server, move repos there (git, not mounts), run sessions in tmux over Tailscale SSH, enable Remote Control for claude.ai and phone. ~/.claude on the server becomes the single home.
- Keep Logic2, FreeCAD, Fusion on the Mac as user-scope HTTP MCP servers over the tailnet — see tailnet-service-exposure-convention.
- JetBrains: Gateway with the Claude Code plugin installed on the host; run a RustRover backend on the server rather than exposing the Mac’s
rustroverMCP. - Hooks run where Claude Code runs, so the reconciler and vault indexer live on the server.
- Routines cannot target a personal machine; use systemd timers with
claude -p. - Auth:
/loginpaste-code flow; credentials in~/.claude/.credentials.json; unsetANTHROPIC_API_KEY. One subscription across your own devices is allowed.
Unverified and risky
Unverified in docs: VS Code Remote-SSH, iTerm
tmux -CCto a remote tmux (see iterm2-tmux-cc-setup), file watching over network mounts. Risk: telep-mainframe’s nvidia_drm modeset crashes would take down the only Claude host — see 2026-08-31-nvidia-drm-host-crash-embedding-pass. Also Serena’s rust-analyzer memory issue on large workspaces.
Immediate hygiene (independent of the graph decision)
Not executed
None of the commands below were run. The vault working tree had 19 modified and 6 untracked paths at the time of writing, unrelated to this research, and
git pull --rebasefails on them. Restoringprojects/alexandriais the user’s decision and was deliberately left alone.
cd ~/levandor_obsidian
git stash list; git status --short # inspect the 19 modified + 6 untracked first
git checkout 93aa1d7^ -- projects/alexandria/ # restore the 5 deleted notes- Symlink
~/.claude/settings.jsoninto dotfiles like CLAUDE.md, so hooks and plugins stop drifting between machines. - Fix or delete
~/.claude/hooks/obsidian-documenter-trigger.sh(the$$counter bug). - Remove claude-mem and episodic-memory from the plugin list, or re-enable claude-mem with an allowed model.
- Add
project/tags to the 295 untagged project notes; merge flat and hierarchical tag forms. - Fix the vault
.gitignorefor.obsidian/plugins/*/data.jsonand set one git identity per machine.
Open decisions for the user
Five open decisions
These are not decided. Nothing below has been acted on.
- Adopt Basic Memory on the vault, or run the convention with a script only.
- Code layer: Serena now, codebase-memory-mcp next, code-graph-rag on the server only if rename detection proves necessary.
- ai-project-brain: narrow to the reconciler (Rust, SQLite, optional MCP), or drop and trial trace-mcp.
- Move Claude Code home to telep-mainframe: yes or no, and whether repos move.
- claude-mem: remove or revive.
Source surveys
Full reports with URLs, dates and comparison tables, filed as separate notes:
- code-graph-survey-2026-09-07 — symbols, calls, SCIP, Serena, codebase-memory-mcp, code-graph-rag
- memory-graph-survey-2026-09-07 — Basic Memory, Graphiti, trace-mcp, claude-mem, temporal validity
- pkm-survey-2026-09-07 — Obsidian’s programmatic surface versus Trilium, Logseq, Anytype, SiYuan, org-roam
- ruflo-evaluation-2026-09-07 — source-level rejection of ruflo
Plus the vault audit, stack audit, prior-art probe, and Claude Code remote-operation notes relayed by the subagents, which are summarised above and not filed separately.
Related
- ai-project-brain — the Rust project this research narrows to a reconciler
- grafeo-feature-matrix — grafeo, which this architecture concludes is unnecessary for the reconciler
- telep-mainframe — proposed single home for Claude Code
- 2026-08-31-telep-kb-mcp-server — the existing vault embedding path, blind to code edits
- tailnet-service-exposure-convention — how Mac-side MCP servers would be exposed after offload
- 2026-08-31-nvidia-drm-host-crash-embedding-pass — the single-host risk in the offload plan
- iterm2-tmux-cc-setup — local tmux setup the offload would extend over SSH
- obsidian-subagent-improvements-2026-05-04 — prior work on the documenter write path