opencode-graphiti is an OpenCode plugin that provides persistent memory for AI agent sessions. It is a two-layer architecture:
- Short-term memory: Continuously extracts structured session events (decisions, tasks, file edits, errors) and rebuilds a priority-tiered snapshot stored in Redis/FalkorDB. This snapshot survives compaction and is re-injected before every LLM call.
- Long-term memory: Asynchronously sends buffered events to Graphiti (a knowledge graph MCP server) in the background. Graphiti results are cached locally in Redis and injected alongside the short-term snapshot for cross-session recall.
Key invariant: Graphiti is never on the hot path. All writes and queries for chat/compaction hooks use only Redis/FalkorDB; Graphiti updates happen asynchronously on idle or after compaction.
- Redis/FalkorDB only. ioredis client at
redis://localhost:6379(configurable). - Stores: session events, snapshots, memory cache, pending drain batches.
- Used by:
chat.message,messages.transform,session.compacting, event handlers.
- Graphiti MCP HTTP endpoint (default
http://localhost:8000/mcp, configurable). - Async drain service: batches buffered events, retries on failure, flushes on idle or post-compaction.
- Background cache refresh: searches Graphiti when topic drift is detected, updates Redis cache.
- Never blocks hook return time.
- Child/subagent sessions resolve to root sessionID via
parentIDchain. - All child events are recorded in the root session's event log.
- Snapshots and
<session_memory>injection reflect combined parent + child activity. - Deleting a child session preserves root state and events.
- chat.message: Session events + snapshot loaded from Redis, cached
Graphiti facts retrieved, composed into
<session_memory>XML, staged for transform hook. - messages.transform:
<session_memory>prepended to last user message (right before LLM call). - Drift detection: Current query vs. cached query; if Jaccard similarity <
driftThreshold(default 0.5), schedule Graphiti cache refresh for next turn. - session.compacting: Same
<session_memory>envelope injected into compaction summary (no fresh Graphiti call).
- User/assistant messages captured as
SessionEventobjects, stored in Redis assession:{id}:events. - Events queued for async drain to Graphiti.
- On idle (
session.idle): drain pending events to Graphiti, rebuild snapshot. - Post-compaction (
session.compacted): schedule async drain and snapshot rebuild.
- See
docs/ReviewProtocol.mdfor the complete workflow. - Detect active PR → fetch unresolved review comments → verify claims → dedupe verified claims into issue classes → run repo-wide class sweeps with conservative parallelization/serialization → resolve threads → push → request fresh review.
- Config loading: Supports
cosmiconfigdiscovery + nestedredis.*andgraphiti.*keys. Seesrc/config.ts. - Redis connectivity: When available, Redis/FalkorDB stores events, snapshots, and cache. If Redis is unavailable, the plugin degrades to in-memory fallback. Graphiti is optional; plugin continues with local-only mode if unavailable.
- Compaction survival: Snapshots and events must persist across compaction
cycles. Test via
docs/SmokeTests.md, the authoritative validation manual. - Concurrency: Multiple child sessions should not corrupt root snapshot. Serialize child event writes to avoid race conditions.
- Session root resolution: Parent ID chain walk must not infinite-loop; validate chain structure to avoid cycles.
- Event ordering: Redis LPUSH/LRANGE preserve order, but concurrent writes risk out-of-order injection if not serialized.
- Snapshot budget: Priority-tiered snapshot has hard limits
(
SNAPSHOT_BODY_BUDGET,PERSISTENT_MEMORY_BODY_BUDGET). Oversized events may be truncated; monitor via test suite. - Drain batch retry logic: Failed Graphiti writes retry up to
drainRetryMaxtimes (default 3). Dead-lettered entries are retained in Redis dead-letter storage but not automatically recovered. - Cache stale reads: On Graphiti unavailability, cached facts may be stale; no explicit cache invalidation exists.
When starting work, read in this order:
- This file (AGENTS.md) — overview and boundaries.
- README.md (§1–4) — detailed motivation, architecture, injection format, workflows.
- docs/ReviewProtocol.md — if handling PR reviews.
- src/index.ts — plugin entry point; see which services are instantiated and how.
- src/session.ts — session ID resolution, memory composition, root-finding logic.
- src/handlers/ — event capture, chat injection, compaction, message transform.
- src/services/ — Redis clients, batch drain, Graphiti async worker, cache management.
- docs/SmokeTests.md — authoritative runtime validation manual and smoke test entry point.
- deno.json — dependencies and build tasks.
Default config file locations (cosmiconfig order):
- Project:
package.json#graphiti,.graphitirc,graphiti.config.* - Home:
~/.graphitirc,~/.config/graphiti/* - Legacy:
~/.config/opencode/.graphitirc
Canonical shape (nested):
Endpoint values must resolve to valid URLs. Config loading performs best-effort
coercion by adding the expected scheme when omitted and defaulting the port only
for scheme-less inputs that do not already include one (6379 for Redis and
8000 for Graphiti); explicit disallowed schemes still fail validation.
| File | Purpose |
|---|---|
src/index.ts |
Plugin factory; wires all services. |
src/session.ts |
Session root resolution, memory composition, XML rendering. |
src/handlers/chat.ts |
chat.message hook; prepares <session_memory>. |
src/handlers/messages.ts |
messages.transform hook; injects into LLM message. |
src/handlers/compacting.ts |
session.compacting hook; injects for summarization. |
src/handlers/event.ts |
Event capture from all message hooks. |
src/services/redis-cache.ts |
Graphiti cache, drift detection, TTL. |
src/services/redis-events.ts |
Event list storage, cleanup. |
src/services/graphiti-async.ts |
Async drain worker, Graphiti interaction. |
src/services/connection-manager.ts |
Graphiti MCP health checks. |
src/services/batch-drain.ts |
Event batching, retry logic. |
docs/SmokeTests.md |
Authoritative runtime validation manual and smoke tests. |
docs/ReviewProtocol.md |
PR review handling workflow. |
Last Updated: 2026-03-25
{ "redis": { "endpoint": "redis://localhost:6379", "batchSize": 20, "batchMaxBytes": 51200, "sessionTtlSeconds": 86400, "cacheTtlSeconds": 600, "drainRetryMax": 3 }, "graphiti": { "endpoint": "http://localhost:8000/mcp", "groupIdPrefix": "opencode", "driftThreshold": 0.5 } }