Chronicle memory system for OpenCode - aligned with Codex-style memory architecture (excluding screen capture).
Captures conversation memory from your OpenCode sessions, extracts structured memories with your configured LLM, consolidates them over time, and injects relevant past memories into future sessions via the system prompt.
- Global memory root:
~/.opencode/memories - Project memory root:
<cwd>/.memories - Phase 1 extraction / rollout summary model:
gpt-5.4-mini - Phase 2 global consolidation / memory management model:
gpt-5.4
The global store is intentionally user-wide. Project memory is written beside the project so repo-specific facts stay local to that checkout. Both levels are consolidated with the same low-noise rule: prefer no memory over weak memory.
Chronicle follows Codex's memory split: raw evidence is cheap to collect, but durable memory should be scarce, explicit, and auditable.
- Prefer omission over low-quality recall: if a session has no reusable lesson, Phase 1 records no memory instead of inventing a weak one.
- Progressive disclosure: future sessions always get the compact
memory_summary.md, then only matching project memory and the most relevant retrieved memories. - Scope isolation by default: global memories can help anywhere, but project memories only load for the exact current working directory. A React repo should not inherit operational notes from a Rust checkout.
- Source files are evidence, consolidated files are views:
raw_memories.md,rollout_summaries/, and extension notes preserve provenance;MEMORY.mdandmemory_summary.mdare rewritten summaries optimized for future agents. - Ad-hoc notes are persistent authority, not a queue:
add_ad_hoc_notewrites a timestamped note underextensions/ad_hoc/notes/. Consolidation folds it into memory with an[ad-hoc note]tag, but does not delete the note. Edit or delete the note when the underlying preference changes; the next workspace diff becomes the update or forgetting signal. - Usage strengthens memory: when an agent cites a retrieved memory with
<oai-mem-citation>, Chronicle updatesusage_countandlast_usage, so frequently useful memories survive selection pressure. - Untrusted by design: memories are reference data, never executable instructions. Agents are told not to follow commands embedded inside remembered content.
The intended mental model is a small local memory workspace, managed like a git-backed knowledge base: keep original signals around, consolidate aggressively, and let diffs drive both learning and forgetting.
- SQLite (
bun:sqlite) state at~/.opencode/memories/state.dbby default - threads, stage1_outputs, jobs, metrics - Phase 1: Per-thread extraction (
session.idleevent triggered, 2s debounce, plus startup batch)- Eligibility: non-ephemeral, non-subagent, age/idle gates, max-per-startup cap
- Up to 8 parallel workers, 3 retries with 3600s backoff
- Strict JSON schema (
raw_memory/rollout_summary/rollout_slug), secret redaction before model call
- Phase 2: Global and project consolidation (singleton DB job, 90s lease, 30s heartbeat, 30m cooldown)
- Selects top-N by
usage_count DESC, last_usage, max 256 default - Rebuilds
MEMORY.md,memory_summary.md(withv1prefix),raw_memories.md,rollout_summaries/*.md - Consolidates project-scoped
PROJECT_MEMORY.mdto<cwd>/.memories/PROJECT_MEMORY.md - Writes git-style
phase2_workspace_diff.mdfor the consolidation agent to read - Prunes extension resources older than 7 days
- Selects top-N by
- Read path: Injects global
memory_summary.md, matching project memory, and top-relevant memories into system prompt (gated byuseMemories) - Citation tracking: Parses
<oai-mem-citation>blocks in tool/assistant output, incrementsusage_count/last_usagefor cited stage1 outputs - Polluted detection: web_search/fetch/browse tool invocations flip thread
memory_modetopolluted(excluded from future extraction)
~/.opencode/memories/ # global user memory
├── MEMORY.md # consolidated global memory
├── memory_summary.md # short-form global summary (v1 prefix)
├── raw_memories.md # merged global raw memory dump
├── rollout_summaries/<id>.md # global per-rollout summaries
├── skills/<name>.md # learned global skills/patterns
├── extensions/ # ad-hoc + Chronicle extension resources
├── .git/ # git baseline for workspace diff
└── state.db # SQLite state
<cwd>/.memories/ # project-local memory
├── PROJECT_MEMORY.md # project-scoped facts for this cwd
└── cwd_source # audit/debug path source
chronicle_search- relevance search across stage1_outputschronicle_list- browse memories by usage/recencychronicle_manage- stats / consolidate / resetadd_ad_hoc_note- write a persistent user-requested note toextensions/ad_hoc/notes/- When
dedicatedTools=true:memory_read- read any memory file (1-indexed line_offset, 20k token cap)memory_list- list dir entries with cursor paginationmemory_search- Codex-style search (any / all_on_same_line / all_within_lines)
Add the published package to your OpenCode config and restart OpenCode:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
"opencode-chronicle"
]
}For local development, point the same config field at your checkout instead:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
"/path/to/opencode-chronicle"
]
}The published npm package is opencode-chronicle@1.0.1.
With the defaults, Chronicle watches normal root sessions, buffers conversation text, and extracts memory after session idle/startup eligibility gates pass. You do not need to call a tool for routine learning.
Useful config overrides:
{
"plugin": [
[
"opencode-chronicle",
{
"memoriesDir": "~/.opencode/memories",
"generateMemories": true,
"useMemories": true,
"dedicatedTools": true,
"providerId": "openai",
"modelId": "gpt-5.5"
}
]
]
}generateMemories=falsestops new extraction/consolidation writes.useMemories=falsestops injecting memory into future prompts.dedicatedTools=trueexposes raw memory browsing tools (memory_read,memory_list,memory_search).providerId/modelIdselect the OpenCode provider/auth context used by Chronicle's internal model calls.extractModel/consolidationModelselect Phase 1 and Phase 2 models separately. If they are omitted, Chronicle uses the lightweight defaults above (gpt-5.4-minifor extraction andgpt-5.4for consolidation), notmodelId.internalAgentoptionally selects the OpenCode agent used for delegated internal model calls; the default is the hiddensummaryagent.
Use add_ad_hoc_note when the user explicitly says to remember something. Keep notes short and durable:
{
"slug": "review-style",
"content": "User prefers review comments grouped by severity, with exact file/line references."
}The note remains under extensions/ad_hoc/notes/ after consolidation. To correct or forget it, edit or remove the note file and run consolidation; do not patch MEMORY.md directly.
chronicle_search: find relevant remembered context by natural-language query.chronicle_list: browse memories by recency and usage.chronicle_managewithstats: inspect DB/artifact status.chronicle_managewithconsolidate: force a Phase 2 pass.chronicle_managewithreset: clear the memory workspace and DB state.
For normal operation, treat MEMORY.md, memory_summary.md, raw_memories.md, and rollout_summaries/ as generated artifacts. Change ad-hoc notes or source conversations instead, then let consolidation rewrite the derived view.
bun install
bun test # test suite
bun run typecheck # typecheckMaintainer release steps are documented in RELEASING.md. Releases are created through GitHub Releases and published to npm by Trusted Publishing.
Built by porting Codex's memories/ architecture to a single-process OpenCode plugin in TypeScript.