feat(ingest): Serena memory migration and proactive injection parity
Problem
Two issues observed in practice:
-
Serena memory silo: Serena accumulates project knowledge in
.serena/memories/*.mdfiles that the memory system never sees. When a session uses Serena's tools, those learnings stay in Serena's flat-file store rather than being ingested into the semantic memory DB where they can be recalled, linked, and proactively injected across future sessions. -
Proactive injection imbalance: Serena's
read_memory/write_memorytools get invoked automatically and preferentially because they appear directly in Serena's tool surface. The opencode-memory plugin injects context proactively, but when Serena's memory tools have already fired, the model treats that as sufficient and the richer semantic memory system gets bypassed.
Scope
1. SerenaObserver — Python (src/opencode_memory/ingestion/serena.py)
- Watches
.serena/memories/directories under registered project roots - Parses each
.mdfile: filename →what, body →content, category inferred from content heuristics - Tracks ingest progress by file mtime high-water mark — idempotent on re-run
- Source key:
serena:<project>:<filename>for deduplication - Wired into the daemon's polling loop alongside the existing OpenCode DB and Claude Code observers
2. SerenaObserver — Rust (rust/crates/memory-core/src/ingestion/serena.rs)
- Full parity with the Python observer — same parsing logic, same mtime tracking, same source key scheme
- Added as a third polling arm in
run_daemonalongsideOpenCodeDbObserverandClaudeCodeObserver
3. Historical migration — Python and Rust
run_serena_ingestinhistorical_ingest.py+memory ingest-serenaCLI subcommand (Python)run_ingest_serenaincommands.rs+IngestSerenasubcommand inmain.rs(Rust), mirroringrun_import_claude_native- Both dedupe against existing memories and preserve original file mtime as
created_at
4. Plugin: Serena-aware proactive injection (plugin/src/index.ts)
tool.execute.afterrecords calls to the Serena memory/knowledge tool set (serena_read_memory,serena_write_memory,serena_list_memories,serena_find_symbol,serena_search_for_pattern,serena_find_referencing_symbols,serena_get_symbols_overview,serena_initial_instructions,serena_onboarding)- Relevant argument values (
memory_name,topic,name_path_pattern,substring_pattern,relative_path,content) are queued per session chat.messageconsumes (and clears) the queued terms, folding them into the existinggetProactiveContextquery — one enriched call, no second round-trip, no double-injectionmessages.transform(thinking-aware path) peeks the same queued terms without consuming them
5. Serena → memory mirror (plugin/src/index.ts + memory-client.ts)
serena_write_memorycalls are now also fire-and-forgot intomemory_remember(categoryfact), so Serena onboarding facts become recallable immediately rather than waiting on the next daemon poll cycle- New
MemoryClient.remember()andMemoryClient.sessionStart()HTTP wrappers system.transformnow callsmemory_session_starton the first turn (fire-and-forget) so session-coordination tools see the session from turn one
6. Boot context parity note
- Added a note explaining the two memory systems' complementary roles: Serena = project-local structured knowledge; GHMEM = cross-session semantic recall, decisions, blockers, queue, workflow.
What this is NOT
- Not replacing Serena's memory tools
- Not blocking Serena tool calls — the plugin supplements, never intercepts
- Not adding new MCP tools
Testing
- 25 Python + 22 Rust unit tests for
SerenaObserver(parse, dedup, mtime tracking) - CLI dispatch test in Rust for
ingest-serena - 4 plugin tests (
serena-aware.test.mjs): query enrichment, one-shot consumption, non-Serena tools ignored, multi-call accumulation - Full existing suites re-verified green: 1063 memory-server + 2236 memory-core Rust tests, 250 plugin tests, 5591+ Python tests (excluding pre-existing environment-flaky failures unrelated to this change)
- Not yet covered by automated tests: the
system.transformautosession_startcall and theserena_write_memory→memory_remembermirror (both fire-and-forget, added most recently) — manual verification only so far
Rebased onto latest master (no conflicts, CI green).