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

SystemWhat it isCanonical formGovernance
OmpKeepPersistent, auditable long-term memory for the OMP/pi coding agent (the pi-persistent-intelligence package).JSONL (L1/L2/L3) + SQLite FTS5 + optional qmd semantic indexPatch-governed; evidence + trust gated
HermesBuilt-in turn-budget memory for the Hermes agent (MEMORY.md / USER.md).Plain markdown, char-budget limitedFree-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.tsdefaultRoot() / resolveRoot()), highest → lowest precedence:

  1. OMP_MEMORY_ROOT
  2. OMPKEEP_ROOT
  3. PI_MEMORY_ROOT
  4. legacy ~/.pi/agent/pi-memory/ (used if it exists)
  5. 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 qmd binary via execFile (src/qmd.ts).
  • Deep / hybrid — Reciprocal Rank Fusion of FTS + semantic, weights FTS 0.45 · Semantic 0.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: true

Store: /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): builds cmd = [OMP_CMD, "acp"] (+ --model if set) and launches it with env={**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.md and USER.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_term so it lands in inbox/captured.jsonl as a governed candidate (trust class agent_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) / rendered MEMORY.md, then emit a budget-trimmed § digest back into ~/.hermes/memories/MEMORY.md honoring memory_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.

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 (or OMPKEEP_ROOT) for OMP sessions — already a verified first-class hook in src/paths.ts:22-23,43-44; no code change required for the OMP side.
  • Step 3 — Teach Hermes the JSONL contract. [INFERENCE] replace Hermes’ direct MEMORY.md/USER.md writes with calls into OmpKeep’s write path (memory_write semantics) so Hermes writes governed candidates instead of free markdown. user_profile_enabled maps 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 to memory_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 in inbox/captured.jsonl under 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 add OMPKEEP_HANDOFF=<path> alongside the existing OMP_HOME env, or stream it as the first ACP prompt turn.
  • Step 3 — Consume. The omp acp session 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 new long_term candidates 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.