OmpKeep and Hermes run side-by-side on this host today and never share state. This page maps that proposed bridge only; mnemopi and OMP harness memory remain separate systems. Cross-refs: OMP · OmpKeep.
1. 🧭 Overview
| System | What it is | Canonical form | Governance |
|---|---|---|---|
| OmpKeep | Persistent, auditable long-term memory for the OMP/pi coding agent (the pi-persistent-intelligence package). | JSONL (L1/L2/L3) + SQLite FTS5 + optional qmd semantic index | Patch-governed; evidence + trust gated |
| Hermes | Built-in turn-budget memory for the Hermes agent (MEMORY.md / USER.md). | Plain markdown, char-budget limited | Free-write, flush-on-turns; no audit trail |
They occupy different roots (~/.pi/agent/pi-memory/ vs ~/.hermes/memories/), use different formats, and have no read/write path between them. The only connective tissue is Hermes’ omp-suite plugin dispatching omp acp subprocesses (see §4) — process orchestration, not memory sharing.
2. 🗃️ OmpKeep
Source repo: /home/dv/pi-persistent-intelligence (README.md, index.ts).
OMP integration: /home/dv/.omp/agent/extensions/ompkeep.ts — a TUI/extension layer that statically imports the core logic from ../../../pi-persistent-intelligence/src/* (paths, render, procedure-candidates, …; see ompkeep.ts:99-123).
Root resolution (src/paths.ts → defaultRoot() / resolveRoot()), highest → lowest precedence:
OMP_MEMORY_ROOTOMPKEEP_ROOTPI_MEMORY_ROOT- legacy
~/.pi/agent/pi-memory/(used if it exists) - fallback
~/.omp/agent/omp-memory/
The env-var precedence at the top of this list is the hook the §5 shared-store design relies on.
Live canonical store (verified): /home/dv/.pi/agent/pi-memory/
memory/
L1.identity.jsonl # identity records — never auto-applied
L2.playbooks.jsonl # patch-governed durable rules
profiles.jsonl
evidence.jsonl # content-addressed, bounded excerpts
reinforcement.jsonl
inquiries.jsonl
tombstones.jsonl # content-free deletion markers
projects/dv.jsonl # project-scoped records
daily/ YYYY-MM-DD.md # L3 session logs (freely writable)
inbox/ captured.jsonl # long_term candidates awaiting curation
patches/ patch_*.json # governed mutations
rendered/ MEMORY.md # markdown projection (NOT canonical)
runtime/ context.md, selected_memory.json, injection-stats.json
search/ memory-fts.db # SQLite FTS5 index
sessions/ session-index.jsonl + summaries/Layers (README.md): L1 Identity (ratification only), L2 Playbooks (confidence/evidence gated patches), L3 Session (daily logs, digest-injected). Markdown is a rendered projection — canonical memory is JSONL.
Search stack (verified):
- Keyword — built-in SQLite FTS5 over
bun:sqlite, zero external deps (src/search/fts.ts). - Semantic — delegates to the external
qmdbinary viaexecFile(src/qmd.ts). - Deep / hybrid — Reciprocal Rank Fusion of FTS + semantic, weights FTS
0.45· Semantic0.55,RRF_K = 60(src/search/hybrid.ts).
Tools / command: memory_write (target=daily appends; target=long_term → inbox candidate), memory_read, memory_search (keyword|semantic|deep), scratchpad, session_*; one human hub: /ok (/ok curate, /ok render, /ok handoff [--goal], /ok diagnostics).
⚠️ Distinct, do not confuse:
/home/dv/.omp/agent/memories/--home-dv--/(MEMORY.md,memory_summary.md,raw_memories.md,skills/,rollout_summaries/) is the OMP harness’ own built-in summary memory, a separate markdown store — not the OmpKeep JSONL root above.
3. 📓 Hermes
Root: /home/dv/.hermes/.
Config — config.yaml memory: block (lines 338-345, verified):
memory:
flush_min_turns: 6
memory_char_limit: 2200
memory_enabled: true
nudge_interval: 10
provider: ""
user_char_limit: 1375
user_profile_enabled: trueStore: /home/dv/.hermes/memories/
MEMORY.md(~2.1 KB) — operational learnings, records separated by a§delimiter.USER.md(~1.2 KB) — user profile / preferences, same§delimiter.
This is plain markdown under a hard char budget (memory_char_limit: 2200, user_char_limit: 1375), flushed every ≥6 turns. There is no JSONL canon, no FTS index, no evidence/trust/patch governance, and no audit trail — the inverse of OmpKeep’s model.
4. 🔌 Current Bridge
The only existing link is Hermes’ omp-suite plugin, which orchestrates OMP subprocesses through a Routa lane workflow:
- Plugin:
/home/dv/.hermes/plugins/omp-suite/· domain DB/home/dv/.hermes/omp-suite/routa.db(SQLite, WAL). - The Dev lane auto-dispatches with
dispatch_command: "omp acp"(plugins/omp-suite/dashboard/routes/lanes.py:29). - Spawn path
_spawn_omp_acp(plugins/omp-suite/dashboard/routes/acp.py:40-52): buildscmd = [OMP_CMD, "acp"](+--modelif set) and launches it withenv={**os.environ, "OMP_HOME": ...}.
This is process dispatch, not shared memory. The spawned omp acp session reads/writes its own OmpKeep store; Hermes passes no memory snapshot into the subprocess, and nothing flows back into ~/.hermes/memories/. The two memories stay siloed even while one agent drives the other.
5. 🧪 Proposals
Three designs, each expressed as ordered Steps (no durations). (b) is recommended.
5a. ↔️ Sync bridge
A periodic projector that keeps both stores loosely consistent without merging them.
- Step 1 — Extract. Parse the
§-delimited records from~/.hermes/memories/MEMORY.mdandUSER.md.[INFERENCE]a small adapter normalizes each§block into an OmpKeep candidate shape. - Step 2 — Project Hermes → OmpKeep. Feed each block through
memory_write target=long_termso it lands ininbox/captured.jsonlas a governed candidate (trust classagent_inference/repository_text) — never auto-applied, surfaced at next/ok inbox. - Step 3 — Render OmpKeep → Hermes. Read OmpKeep’s selected memory (
runtime/selected_memory.json) / renderedMEMORY.md, then emit a budget-trimmed§digest back into~/.hermes/memories/MEMORY.mdhonoringmemory_char_limit: 2200. - Step 4 — Schedule.
[INFERENCE]drive the projector from a Hermes cron tick (~/.hermes/cron/) or OmpKeep session-end hook; dedupe on normalized key so re-runs are idempotent.
Trade-off: lowest blast radius, but two stores of record persist and can drift between syncs.
5b. 🏆 Shared store (recommended)
Collapse the silo by pointing both agents at one governed JSONL root.
- Step 1 — Pick the canon. Use the existing OmpKeep root
/home/dv/.pi/agent/pi-memory/(or a neutral~/.shared-memory/). - Step 2 — Repoint OMP. Export
OMP_MEMORY_ROOT(orOMPKEEP_ROOT) for OMP sessions — already a verified first-class hook insrc/paths.ts:22-23,43-44; no code change required for the OMP side. - Step 3 — Teach Hermes the JSONL contract.
[INFERENCE]replace Hermes’ directMEMORY.md/USER.mdwrites with calls into OmpKeep’s write path (memory_writesemantics) so Hermes writes governed candidates instead of free markdown.user_profile_enabledmaps onto OmpKeep L1/profile records (review-gated). - Step 4 — Read via projection. Hermes loads its in-context budget from OmpKeep’s rendered projection (
rendered/MEMORY.md+runtime/selected_memory.json), still clamped tomemory_char_limit/user_char_limit. - Step 5 — Verify. Confirm both agents hit the same root (
/ok doctor), FTS5 stays in sync after writes, and Hermes records appear ininbox/captured.jsonlunder curation.
Trade-off: one source of record, full audit + dedup + tombstones for both agents. Cost: Hermes must adopt the candidate/patch flow instead of free-writing markdown.
5c. 💉 ACP-time injection
Make the existing §4 bridge memory-aware at dispatch.
- Step 1 — Snapshot. Before spawning, generate an OmpKeep handoff via
/ok handoff [--goal <task>](or the underlying snapshot API) scoped to the Dev-lane task. - Step 2 — Attach. In
_spawn_omp_acp(acp.py:40-52),[INFERENCE]pass the snapshot into the child — write it to a temp file and addOMPKEEP_HANDOFF=<path>alongside the existingOMP_HOMEenv, or stream it as the first ACP prompt turn. - Step 3 — Consume. The
omp acpsession loads the snapshot as task context so the dispatched worker starts with the parent’s relevant memory instead of a cold store. - Step 4 — Return path (optional).
[INFERENCE]on lane completion, fold the session’s newlong_termcandidates back through the §5a projector into Hermes.
Trade-off: smallest change to the live workflow and immediately useful for delegated tasks, but per-dispatch only — it doesn’t unify the resting stores.
6. 🗺️ Topology
flowchart LR subgraph OMP["OMP Agent + OmpKeep"] OK["OmpKeep JSONL canon (~/.pi/agent/pi-memory)"] FTS["SQLite FTS5 + qmd RRF"] OK -->|"indexes"| FTS end subgraph HERMES["Hermes Agent"] HM["MEMORY.md / USER.md (char-budget)"] SUITE["omp-suite (routa.db)"] end SUITE -->|"dispatch 'omp acp' (process only)"| OMP HM -.->|"5a: project to long_term candidates"| OK OK -.->|"5a: render budget digest back"| HM HM == "5b: repoint via OMP_MEMORY_ROOT" ==> OK SUITE -.->|"5c: attach /ok handoff snapshot"| OMP
Solid arrow = the only link that exists today; dashed/thick = the three proposals above. See also OMP and OmpKeep.