Mandatory Memory Participation Contract
Status: accepted Date: 2026-03-02 Deciders: Joel Hooks, Panda Related: ADR-0021, ADR-0068, ADR-0077, ADR-0082, ADR-0094
Context
The memory system exists (ADR-0021, ADR-0082) but participation is opt-in. Skills can remind agents to use recall/observe, but nothing enforces it. In practice:
- Sessions start cold when the agent forgets to recall
- Compactions and session ends often skip observation
- There’s no telemetry proving memory is actually being used
- Silent memory failures are invisible — the agent just operates without context
Opt-in memory is no memory. The system has the pipeline but no enforcement.
Reference spec: https://joelclaw.com/the-memory-system.md
Decision
1. Gateway Role Hard Rules
Add to gateway ROLE.md / system prompt as non-negotiable:
- Every session MUST retrieve memory on start. No cold-start sessions. Recall fires automatically.
- Every session MUST observe on compaction and end. No silent sessions. Observations are extracted from every session.
- Recall before responding to any non-trivial human question. Trivial = greetings, acks, heartbeats. Everything else gets a recall check.
- Memory write failures are first-response priority. Same severity as deploy failures. If observe/store fails, fix it before other work.
2. Pi Extension Enforcement
Implement memory hooks in the pi-tools extension (packages/pi-extensions/):
| Hook | Action |
|---|---|
session_start | Auto-fire recall with session context seed query |
agent_start | Inject recall results into first-turn context |
| compaction event | Auto-fire observe on compacted content |
session_shutdown | Auto-fire observe on session transcript |
tool_call (recall) | Wrap with OTEL span, log query + params |
tool_result (recall) | Tag results with retrieval metadata (count, latency, budget) |
| observe failure | Emit error OTEL event, log to gateway |
The extension makes memory participation involuntary. The agent doesn’t choose to remember — the harness ensures it.
3. OTEL Instrumentation
Every memory operation emits structured telemetry to the otel_events collection:
Recall events:
memory.recall.started— query, budget profilememory.recall.completed— result count, latency_ms, top categoriesmemory.recall.failed— error, query
Observe events:
memory.observe.started— session_id, trigger (compaction/shutdown)memory.observe.completed— facts extracted, allow/hold/discard counts, duration_msmemory.observe.failed— error, session_id
Write gate events:
memory.gate.decision— observation hash, verdict, confidence
Health targets (enforced via o11y triage):
- Sessions without recall: 0
- Sessions without observe: 0
- Observe failure rate: < 5%
- Recall p95 latency: < 3s
Consequences
Good
- Memory becomes structural, not behavioral — can’t be forgotten
- OTEL proves actual usage, not just capability
- Extension hooks are the enforcement layer — no prompt compliance needed
- Health targets make memory regressions visible in o11y triage (ADR-0090)
Tradeoffs
- Extension complexity increases — more hooks, more failure modes
- Recall on every session start adds latency (~1-3s)
- Observe on every compaction adds inference cost
- If the memory pipeline is down, sessions may be blocked or degraded
Mitigations
- Recall has hard timeout (3s) — degrade to no-memory rather than block
- Observe is async — doesn’t block session end, fires as background Inngest function
- Circuit breaker: if memory pipeline has >3 consecutive failures, degrade gracefully and emit alert
Implementation Sequence
- ADR-0195 accepted ← here
- Update gateway ROLE.md with hard rules
- Implement extension hooks in pi-tools (session_start recall, shutdown observe)
- Add OTEL spans to recall/observe tool calls
- Add health targets to o11y triage patterns
- Verify with
joelclaw otel search "memory."— all events flowing - Monitor for 7 days, tune timeouts and circuit breaker thresholds
2026-03-04 Reality Check
Status updated to shipped.
What’s running
~/.pi/agent/extensions/memory-enforcer/index.ts— pi extension in productionsession_starthook: firesjoelclaw recallwith seed query, injects results into first turnsession_shutdownhook: firesmemory/observe.requestedviajoelclaw sendbefore_agent_starthook: queriessystem_knowledgeviajoelclaw knowledge search- OTEL events emitted:
memory.recall.started/completed/failed,memory.observe.requested/failed,system_knowledge.retrieval.started/completed/failed
Gap: no automated verification of hook success rate
- OTEL events exist but no scheduled check compares “sessions started” vs “recalls fired”
- knowledge-watchdog (every 4h) checks retrieval events in window but not session-level coverage
- Next step: add session coverage check to knowledge-watchdog (ADR-0200 F/E/V verify layer)