# v8.2 Design: Temporal Memory Tree + Multi-Graph Memory + Graph Recall

> Status note (2026-03-08): Active roadmap order, blockers, and contributor priority live in the [Engram Feature Roadmap](https://github.com/users/joshuaswarren/projects/1). This file is historical design context and may describe scope that is only partially shipped.

**Date:** 2026-02-22
**Plan codename:** Release C — v8.2 (Tree + Graph Reasoning)
**All features default to `false`.**

---

## Goals

Extend Engram's retrieval substrate from flat ranked lists into a hierarchical + graph-connected structure so that:

1. **Temporal Memory Tree (TMT):** Long-horizon queries get a compressed, hierarchical view of memory history without flooding the context window.
2. **Multi-graph memory:** Related memories are connected by typed edges (entity co-reference, temporal sequence, causal inference) enabling lateral retrieval beyond cosine similarity.
3. **Graph recall mode:** A new planner mode activates graph expansion after QMD retrieval, with an explainability tool to show what was retrieved and why.

All capabilities ship behind feature flags and fail-open to the existing baseline recall path.

---

## PR Structure

Use small, reviewable slices. The original PR numbers below are logical labels; GitHub PR numbers may differ.

```
PR 17 (TMT)    ──┐
PR 18 (Graph)  ──┘
       │
       ├──► PR 19A (Planner + graph_mode gating only)
       ├──► PR 19B (Spreading activation retrieval integration)
       ├──► PR 19C (Explainability tools + snapshots)
       └──► PR 19D (Hardening, perf guardrails, rollout docs)
```

---

## PR 17 — Temporal Memory Tree

**Flag:** `temporalMemoryTreeEnabled` (default `false`)
**New file:** `src/tmt.ts`
**New store:** `memory/tmt/`

### Node Hierarchy

| Level | File path | Trigger |
|-------|-----------|---------|
| Hour | `tmt/YYYY-MM-DD/hour-HH.md` | Consolidation run when `>= tmtHourlyMinMemories` new memories exist for that hour |
| Day | `tmt/YYYY-MM-DD/day.md` | Built/updated during daily consolidation from hour nodes |
| Week | `tmt/week-YYYY-WW.md` | Built/updated from day nodes when week rolls |
| Persona | `tmt/persona.md` | Rebuilt from recent weeks during weekly consolidation |

### Summarization

Uses the same local LLM path as hourly summaries (no extra API cost by default). Prompt instructs the model to produce a 3–5 sentence narrative summary of the memories, preserving key facts, decisions, and preferences. Each node stores YAML frontmatter: `level`, `periodStart`, `periodEnd`, `memoryCount`, `sourceIds[]`.

### Recall Injection

When `temporalMemoryTreeEnabled`, the recall assembler injects the most applicable TMT node just before the episodes/boxes section. Selection logic: match query temporal signals against node `periodStart/End`; fall back to most recent day node. Injection is skipped when `recallPlannerEnabled` resolves to `no_recall` or `minimal`.

### Config Additions

- `temporalMemoryTreeEnabled` — master flag (default `false`)
- `tmtHourlyMinMemories` — min new memories to trigger an hour node (default `3`)
- `tmtSummaryMaxTokens` — max tokens for a TMT summary (default `300`)

---

## PR 18 — Multi-Graph Memory

**Flag:** `multiGraphMemoryEnabled` (default `false`)
**New file:** `src/graph.ts`
**New store:** `memory/state/graphs/{entity,time,causal}.jsonl`

### Graph Types

| Type | Edges represent | Built from | File |
|------|----------------|------------|------|
| **Entity** | Two memories share a named entity | Existing `entityRef` frontmatter + entity files | `entity.jsonl` |
| **Time** | Memory A temporally precedes memory B (within a session) | `created` timestamps + `threadId` | `time.jsonl` |
| **Causal** | Memory A caused/led to memory B | Heuristic keyword extraction (`because`, `therefore`, `caused`, `led to`, `as a result`) — LLM optional | `causal.jsonl` |
| **Semantic** | Deferred — QMD already handles semantic similarity | — | — |

### Edge Format (JSONL)

```json
{"from": "facts/2026-02-22/abc.md", "to": "facts/2026-02-22/def.md", "type": "entity", "weight": 1.0, "label": "project-x", "ts": "2026-02-22T10:00:00Z"}
```

### Graph Building

- **Entity graph:** Built incrementally during `indexMemory` — when a new memory has `entityRef`, add edges to all other memories sharing that entity (capped at `maxEntityGraphEdgesPerMemory`, default 10).
- **Time graph:** Built during extraction — connect consecutive memories within the same `threadId` or session window.
- **Causal graph:** Built post-extraction — scan new memory content for causal signal phrases; if found, link to the most recent memory in the same session as a causal predecessor.

### Spreading Activation (SYNAPSE-inspired)

```
spreadingActivation(seeds: string[], maxSteps: number, decayFactor: number): string[]
```

BFS from seed node IDs. At each hop, collect neighbors from all enabled graph types. Apply `weight × decay^hop` scoring. Inhibit nodes already in the seed set. Return top-N by activation score, bounded by `maxGraphTraversalSteps`.

### Config Additions

- `multiGraphMemoryEnabled` — master flag (default `false`)
- `entityGraphEnabled` — enable entity graph (default `true` when master is on)
- `timeGraphEnabled` — enable time graph (default `true` when master is on)
- `causalGraphEnabled` — enable causal graph (default `true` when master is on)
- `maxGraphTraversalSteps` — max BFS hops (default `3`)
- `graphActivationDecay` — per-hop decay factor (default `0.7`)
- `maxEntityGraphEdgesPerMemory` — cap on entity edges per write (default `10`)

---

## PR 19 — Graph Recall Mode + Explainability

**Flag:** `graphRecallEnabled` (default `false`)
**Depends on:** PR 17 (TMT injection path) + PR 18 (graph traversal)

### PR 19 Slice Plan

#### PR 19A — Planner + mode gating (no retrieval behavior expansion)
- Add `graph_mode` as a planner outcome when graph flags are enabled and query signals qualify.
- Keep recall output equivalent to existing path (no graph expansion yet).
- Add tests for mode reachability + disabled-path parity.

#### PR 19B — Graph expansion integration
- Use top QMD hits as seeds and call `spreadingActivation`.
- Merge graph-expanded candidates with QMD candidates and re-rank with capped limits.
- Add timeout/fail-open behavior so graph expansion can never block baseline recall.

#### PR 19C — Explainability + debug tooling
- Add `memory_graph_explain_last_recall` and persist `state/last_graph_recall.json`.
- Add/extend `memory_intent_debug` output with planner-mode reasons and provenance.
- Add tests for missing/corrupt snapshot fail-open behavior.

#### PR 19D — Hardening + rollout
- Tune guardrails (caps, traversal steps, decay defaults, telemetry logging).
- Run PR hardening gate and add rollout guidance.
- Keep all graph recall behavior behind config flags until merge.

### Graph Planner Mode

The existing recall planner (`recallPlannerEnabled`) adds a fourth decision: `graph_mode`. Triggered when:
- `graphRecallEnabled` is true, AND
- `multiGraphMemoryEnabled` is true, AND
- Query has multi-hop signals: entity names, causal language, or is classified as `multi_hop`

In `graph_mode`:
1. Run standard QMD hybrid retrieval (same as `full` mode).
2. Use the top QMD results as seeds for spreading activation.
3. Merge graph-expanded candidates with QMD results (union, re-ranked by combined score).
4. Apply `recallResultLimit` cap as usual.
5. Record the graph expansion path to `state/last_graph_recall.json`.

### New Tools

**`memory_graph_explain_last_recall`**
- Reads `state/last_graph_recall.json`
- Returns: QMD seed nodes, graph expansion path (node → edges → neighbors), final ranked list with provenance labels
- Available whenever `graphRecallEnabled` is true

**`memory_intent_debug`**
- Reads `state/last_intent.json` (written by the existing intent module on each turn)
- Returns: detected intent goal/action/entity types, planner mode decision, boost scores applied
- Available whenever `recallPlannerEnabled` is true

### Snapshot State Files

- `memory/state/last_graph_recall.json` — last graph expansion path (overwritten each turn)
- `memory/state/last_intent.json` — last intent classification (overwritten each turn, already partially exists)

---

## Failure Modes + Fail-Open Guarantees

| Failure | Behavior |
|---------|----------|
| TMT node write fails | Logged, consolidation continues |
| TMT node missing | Recall proceeds without TMT injection |
| Graph edge write fails | Logged, memory write still succeeds |
| Graph files corrupt/missing | `spreadingActivation` returns empty, QMD results used as-is |
| Graph expansion timeout | Abort expansion, return QMD-only results |
| `state/last_graph_recall.json` missing | Tool returns "no graph recall recorded yet" |

All features are strictly additive — disabling any flag restores baseline behavior exactly.

---

## Testing Requirements

Each PR ships with:
- Unit tests for the new module (`tmt.test.ts`, `graph.test.ts`)
- Integration test: feature disabled → baseline behavior unchanged
- Integration test: feature enabled → expected nodes/edges written
- Quick-preflight test: fail-open on corrupted state files
