Memory Graph Architecture
How graph nodes and edges are extracted, stored, retrieved, and guarded in memories.sh.
This page describes the graph pipeline end-to-end: write path, storage model, hybrid retrieval, and rollout guardrails.
Why The Graph Exists
Baseline retrieval ranks memories by text relevance. The graph layer adds relationship traversal so related memories can be recalled even when exact query terms differ.
Examples:
- Query mentions
rollout alarms, but the best supporting memory is connected throughtopic:dashboard. - Query mentions
hybrid strategy, and relateddecisionorrulememories are reached through graph edges instead of keyword overlap.
Storage Model
Graph storage is maintained in the workspace Turso database:
graph_nodes: canonical entities (memory,repo,topic,category,memory_type, etc.)graph_edges: typed, weighted directional relationships between nodesmemory_node_links: mapping between each memory and its extracted nodes
Every memory is also represented as a first-class memory node (node_key = memory_id) and linked back with role self. This enables direct memory-to-memory edges in later graph phases without schema changes.
Primary code paths:
/Users/tradecraft/dev/memories/packages/web/src/lib/memory-service/graph/upsert.ts/Users/tradecraft/dev/memories/packages/web/src/lib/memory-service/graph/retrieval.ts/Users/tradecraft/dev/memories/packages/web/src/lib/memory-service/graph/status.ts
Write Path
- A memory write/update enters memory mutation handlers.
- Graph extraction produces node and edge candidates from memory content and metadata, including the memory's own
memorynode. upsert.tsensures schema, upserts nodes, writes memory-node links (self,type,tag, etc.), writes evidence-backed edges, and prunes stale links for edited/forgotten memories.- When embeddings are available, similarity sync writes bidirectional
similar_toedges between memory nodes for high-cosine neighbors. If LLM extraction is enabled, ambiguous-neighbor pairs are additionally classified intocontradictsorsupersedes. - Cleanup removes orphan graph nodes with no links or edges.
Behavior is best-effort: memory writes stay available even if graph indexing fails.
Read Path (Hybrid Retrieval)
Hybrid retrieval runs in layered recall logic:
- Baseline candidates are gathered from rules, working memories, and long-term memories.
- If request strategy is
hybrid_graphand rollout allows it, graph expansion traverses related nodes/edges from seed memories. - Graph-expanded memories are appended with provenance metadata (
whyIncluded: graph_expansion, linked node, edge type, hop count). - If graph expansion errors or rollout disallows application, retrieval falls back safely to baseline.
Graph expansion can include semantically related memories via similar_to edges, even without shared tags/categories.
Graph candidate ranking is edge-type aware and confidence-weighted. For equal hop counts, higher-priority relationships (for example caused_by, contradicts, supersedes) outrank generic relational links.
Edge Weight Table
The retrieval ranker applies edge-type multipliers before hop decay:
| Edge type | Weight | Why |
|---|---|---|
caused_by | 1.5 | Causal updates should dominate older generic preference facts |
contradicts | 1.3 | Surface conflicts quickly for clarification |
supersedes | 1.2 | Prefer newer refinement over stale variants |
similar_to | 1.0 | Semantic neighbor baseline |
depends_on | 0.9 | Preserve workflow ordering context |
prefers_over | 0.8 | Preference edges with lower certainty than causal updates |
specializes | 0.7 | Hierarchical narrowing |
conditional_on | 0.6 | Condition-gated relationships |
shared_node | 0.25 | Legacy/shared metadata traversal fallback |
Ranking formula:
score = (edge_type_weight * edge_weight * confidence) / max(1, hop_count)At equal confidence and hop count, caused_by will outrank prefers_over, which is how causal facts can override older stated preferences.
Fallback reasons include:
feature_flag_disabledrollout_offshadow_modequality_gate_blockedgraph_expansion_errorrollout_guardrail
Rollout And Safety Controls
Workspace rollout mode controls whether hybrid expansion is applied:
off: baseline onlyshadow: execute graph path for metrics, return baselinecanary: apply graph expansion forstrategy: hybrid_graphrequests
Safety and observability are emitted through graph status and trace payloads:
/api/sdk/v1/graph/status/api/sdk/v1/graph/rollout/api/sdk/v1/graph/trace
Canary mode is also protected by a quality gate that evaluates fallback and relevance regressions over rolling windows before allowing canary application.
Similarity Edge Configuration
Similarity edge extraction is controlled by environment variables:
SIMILARITY_EDGE_THRESHOLD(default0.85): cosine score cutoff forsimilar_toedge creation.SIMILARITY_EDGE_MAX_K(default20): max candidate embeddings scanned per write.SIMILARITY_EDGE_MAX_PER_MEMORY(default5): max neighbors retained per memory after ranking.
LLM Relationship Extraction Configuration
When GRAPH_LLM_EXTRACTION_ENABLED=true, ambiguous similarity matches can be classified into additional relationship edges:
contradicts: bidirectional conflict relationship.supersedes: directional "newer memory refines older memory" relationship.- semantic extraction edges:
caused_by,prefers_over,depends_on,specializes,conditional_on.
conditional_on edges link memories to shared condition nodes (for example time:morning), which are auto-created and reused during graph upsert.
Environment controls:
GRAPH_LLM_AMBIGUOUS_SIMILARITY_MIN(default0.70)GRAPH_LLM_AMBIGUOUS_SIMILARITY_MAX(default0.90)GRAPH_LLM_RELATIONSHIP_CONFIDENCE_THRESHOLD(default0.70)GRAPH_LLM_RELATIONSHIP_MODEL_ID(defaultanthropic/claude-3-5-haiku-latest)GRAPH_LLM_SEMANTIC_CONTEXT_LIMIT(default20)GRAPH_LLM_SEMANTIC_CONFIDENCE_THRESHOLD(default0.60)GRAPH_LLM_SEMANTIC_MIN_CHARS(default20)
Contradiction Detection Pipeline
Contradiction/refinement extraction runs in the async embedding worker:
- Compute similarity neighbors from
memory_embeddings. - Filter to ambiguous matches using
GRAPH_LLM_AMBIGUOUS_SIMILARITY_MIN..MAX. - Classify each pair as
agrees,contradicts,refines, orunrelated. - Persist only edges meeting
GRAPH_LLM_RELATIONSHIP_CONFIDENCE_THRESHOLD.
Outputs:
contradicts(bidirectional memory-memory edge)supersedes(directional memory-memory edge)
Semantic Relationship Extraction Pipeline
Semantic extraction also runs asynchronously in the embedding worker and does not block memory writes:
- Select recent scoped memories (
GRAPH_LLM_SEMANTIC_CONTEXT_LIMIT). - Send new-memory + recent-memory context to the configured model with strict JSON schema output.
- Parse + validate typed edges (
caused_by,prefers_over,depends_on,specializes,conditional_on). - Drop low-confidence edges (<
GRAPH_LLM_SEMANTIC_CONFIDENCE_THRESHOLD). - Persist edges with evidence metadata; map
conditional_onto sharedconditionnodes.
Cost And Operations Note
Enabling GRAPH_LLM_EXTRACTION_ENABLED adds model calls per memory write (pairwise ambiguous classification + semantic extraction pass). These calls run in background embedding jobs and are best-effort.
Operationally:
- memory writes still succeed if extraction fails
- extraction failures are logged as best-effort degradation and surfaced in embedding job metrics as
GRAPH_RELATIONSHIP_PARTIAL_DEGRADE - issue-level extraction codes are recorded (
GRAPH_LLM_CLASSIFICATION_FAILED,GRAPH_LLM_SEMANTIC_EXTRACTION_FAILED) to make rollout regressions visible - retries after
GRAPH_RELATIONSHIP_SYNC_FAILEDreuse stored embeddings when available to avoid repeated embedding API calls for graph-only failures - monitor AI Gateway usage when enabling this in high-write tenants
- embedding usage endpoints currently report embedding spend, not a separate semantic-extraction meter
Scope And Workspace Routing
Graph data respects the same routing model as memories:
tenantId: AI SDK Project selector (security/database boundary)userId: end-user scope insidetenantIdprojectId: optional project/repo context filter (not an auth boundary)
When workspace repo-routing mode is auto, org repos route to org workspace memory and personal repos route to personal workspace memory by default.
You can also set explicit owner mappings in Settings → Repo Workspace Routing to handle org-owned repos that do not match your workspace slug.
Examples:
projectId: "github.com/jane/side-project"with no mapping routes to personal memory.projectId: "github.com/webrenew/memories"routes to thewebreneworg workspace when you are a member.- Mapping
acme-platform -> org_acmeroutesprojectId: "github.com/acme-platform/backend"to the selectedorg_acmeworkspace even if the slug differs.
Dashboard Explorer Mapping
The dashboard graph explorer (Memory Graph section) reads from /api/graph/explore and renders:
- Relationship graph (interactive node/edge view)
- Selected edge metadata (direction, weight, confidence, evidence, expiry)
- Linked memories and evidence highlighting
This view is designed for debugging retrieval quality and data linkage, not only for health checks.