Memories aren't a flat blob — they're a graph. 6 relation variants at v0.7.0 (related_to, supersedes, contradicts, derived_from, plus the v0.7 additions reflects_on for recursive-learning + derives_from for atomisation atom→parent links), an entity registry that resolves alias-to-canonical-name, temporal validity on every edge so the past stays queryable + Ed25519 per-link attestation populated, and an 11-tool graph MCP family at v0.7.0 headlined by the four dedicated KG query tools (memory_kg_query, memory_kg_timeline, memory_kg_invalidate, memory_find_paths; the family also carries memory_link, memory_entity_register, memory_entity_get_by_alias, memory_get_taxonomy, memory_load_family, memory_replay, memory_verify). v0.6.3 Streams B + C laid the foundation; v0.7.0 ships the Apache AGE Cypher backend (auto-detected when the AGE Postgres extension is installed) — what was "planned" in v0.6.x is now a feature gate.
Every memory is a node. Every memory_link row is a directed edge with a typed relation and (since v0.6.3) a temporal validity window. The graph is queryable via recursive CTE on the sqlite backend, and via Apache AGE Cypher on the postgres backend (shipped at v0.7.0).
Every memory_link row carries one of these six relation tags at v0.7.0 (was four at v0.6.x; reflects_on joined the set with recursive-learning Task 1/8 and derives_from joined with WT-1-A atomisation). The six canonical names always pass; since v0.7.0 Wave-3 Continuation 5, validate_relation additionally accepts any caller-supplied lowercase [a-z0-9_]+ identifier (mirroring the AGE Cypher edge-label convention) — whitespace, control chars, and shell metacharacters are still rejected.
Generic association. The default. "These memories are about the same thing." No semantic claim beyond "look at both."
The newer memory replaces the older. The graph captures the supersession explicitly so recall can prefer the latest.
Explicit disagreement. Often auto-created by memory_detect_contradiction (LLM-driven). Surfaces conflicts on recall.
Consolidation provenance. Used by memory_consolidate to link N source memories to the consolidated output. Audit chain stays intact.
Recursive-learning provenance. Used by memory_reflect to link a reflection to the lower-depth peers it was synthesised over. Bounded by reflection_depth caps so the recursion can't run away.
reflects_on each daily journal in the periodAtomisation provenance (WT-1-A). Distinct from derived_from — atomisation is a finer-grained, recoverable split that emits one derives_from edge per atom, while consolidation merges several memories into one and emits derived_from edges.
derives_from its parent long-form memorySchema v15 (v0.6.3) added four nullable columns to memory_links: valid_from, valid_until, observed_by, and signature. v0.7.0 populates the signature column with Ed25519 per-link attestation (was placeholder pre-v0.7) — links now carry cryptographic provenance + attest_level (unsigned / self_signed / peer_attested / signed_by_peer / daemon_signed — the H4 AttestLevel enum). Edges carry a temporal window — "this relation was true between Mar 15 and Apr 20." Past states stay queryable via memory_kg_timeline; the present query (memory_kg_query) walks only currently-valid edges.
Entities are first-class. An entity is a long-tier memory tagged entity with metadata.kind = "entity"; its aliases live in the entity_aliases side table. memory_entity_register creates one (idempotent on (canonical_name, namespace)); memory_entity_get_by_alias resolves any alias to the canonical entity.
(canonical_name, namespace) — re-registering reuses the entity_id and merges new aliases via INSERT OR IGNORE. A non-entity memory occupying the same (title, namespace) hard-errors rather than letting the upsert silently overwrite unrelated content.valid_until = now(). The edge stays in the database (memory_kg_timeline still surfaces it) but disappears from memory_kg_query's present-tense walk. Past-state queries with as_of < valid_until continue to traverse it.v0.6.3's KG queries use Postgres recursive CTEs (or SQLite WITH RECURSIVE). Performance is fine up to a few hundred thousand edges; past that, Apache AGE's Cypher engine is materially faster on graph workloads. v0.7 Bucket 2 (per the v0.7 charter) wraps v0.6.3's KG schema with AGE and replaces the dual-path stubs that v0.6.3 ships as scaffolding.
memory_consolidate collapses 12 weekly notes into one retro, the original 12 don't disappear from the audit trail — each gets a derived_from edge to the retro. "Show me the source memories for this consolidated decision" is a one-query KG walk.contradicts edge surface together on recall. The agent sees the conflict; the operator decides which is current via supersedes.as_of on KG queries returns the graph as it was at any past moment — useful for "what did we believe last quarter?" forensics. Without temporal validity columns, this requires a snapshot-based backup strategy.