Memory extension — mem0 vs hindsight
Memory extension — mem0 vs hindsight
Young, 2026-10-20: "Revisit Memory study… We need to extend our agents memory as Hermes had limitation. mem0 would be great candidate, check self host and license. Goal is to host on LAB, Pulse can connect to it."
Answer in one line: both are licence-clean and both are already in Hermes' official plugin catalog with pinned SHAs, so adoption is a one-command install — but they are mutually exclusive on one Hermes venv (a real dependency conflict, below), Docker is not installed on LAB, and only one of them is designed to be reached across a network. Recommendation at the end: hindsight, with mem0 as a cheap fallback spike.
1. The most important finding: this is not a build, it is an install
The previous mem0-study (2026-10-13) recommended "study-only, no adoption." Two
things have changed since, and both matter more than the repos themselves:
- Nous moved every memory provider out of the Hermes core tree into a curated
plugin catalog.
hermes memory --helpnow says: "Catalog providers (e.g. honcho, hindsight, supermemory, mem0, openviking):hermes plugins install <name>. Only one external provider can be active at a time." - Both repos ship first-party Hermes plugins, and both are pinned in our own catalog on disk:
| mem0 | hindsight | |
|---|---|---|
| Catalog entry | plugin-catalog/mem0.yaml | plugin-catalog/hindsight.yaml |
| Pinned SHA | 43849c6e9d4d… | d56c4acdf59c… |
| Plugin version | 1.3.0 | 1.2.3 |
| Plugin path | integrations/hermes-plugin-mem0/ | hindsight-integrations/hermes/ |
| Catalog tier | community | community |
| Maintainer | mem0ai | vectorize-io |
requires_hermes | — | >=0.21.4 |
Our Hermes is v0.21.6+195 — satisfies hindsight's floor. hermes plugins search
returns both. So the install path is hermes plugins install mem0 (or
hindsight), then hermes memory setup. No integration work is owed by us.
This reframes the study: the question is no longer "can we integrate a memory layer?" — it is "which of two catalog providers do we run, and where?"
2. Licence — both clean, but mem0 is open-core
Verified from the LICENSE files in the clones, not from README badges:
| mem0 | hindsight | |
|---|---|---|
| Repo licence | Apache-2.0 ✅ | MIT ✅ |
| Secondary/copyleft licence files | none | none |
pyproject licence field | Apache-2.0 | MIT |
| Bundled images | pgvector/pgvector:pg17 (PostgreSQL Licence) | pgvector/pgvector:pg18, ghcr.io/vectorize-io/hindsight |
Neither stack contains AGPL, SSPL, BUSL or a proprietary network-service licence. That is the licence-clean test our rule requires, and both pass. This is the one clear "yes" in the study.
⚠️ But mem0's self-host is open-core — and the benchmark is the platform's
mem0's own README comparison table:
| Library | Self-Hosted Server | Cloud Platform | |
|---|---|---|---|
| Dashboard | -- | Yes | Yes |
| Auth & API Keys | -- | Yes | Yes |
| Advanced Features | -- | "Teasers" | "All included" |
And on the numbers everyone quotes (92.5 LoCoMo / 94.4 LongMemEval):
"Scores reflect Mem0's managed platform, which includes proprietary optimizations not available in the open-source SDK; open-source users should expect directionally similar gains but not identical numbers."
Confirmed in their code, not just the README — integrations/hermes-plugin-mem0/_backend.py:94:
# rerank is platform-only; the self-hosted /search ignores it.
So: self-hosting mem0 means running the tier that is explicitly sold as the reduced one. The licence is clean; the capability is gated. That distinction is the whole point of this section — Apache-2.0 tells you what you may do with the code, not whether the code is the product.
hindsight shows no equivalent gating — I found no "platform-only" markers in its repo, and its MIT licence covers the whole tree. Its LongMemEval SOTA claim carries a stronger provenance line than mem0's: "independently reproduced by research collaborators at the Virginia Tech Sanghani Center… and The Washington Post. Other scores are self-reported by software vendors." ⚠️ That is still their claim about their own product — I did not reproduce it, and I do not treat vendor benchmarks as deciding facts.
3. 🔴 The decisive constraint: they cannot coexist
This is the finding that turns the study from "which is better" into "pick one."
hindsight's own Hermes plugin README, explaining why it ships a slim client instead of the full package:
"
hindsight-allpulls the wholehindsight-api-slimtree, which cannot resolve against Hermes' pinned extras: api-slim needsprotobuf>=7.35.1whilemem0ai==2.0.10andmodal==1.5.5cap it below 7.0, andopentelemetry-semantic-conventions>=0.65b0whilemistralai==2.4.8caps it below 0.61. Relaxing one pin only uncovers the next."
mem0's plugin declares mem0ai>=2.0.10,<3 (verified in its pyproject.toml).
So: mem0 pins protobuf<7.0; hindsight's API needs protobuf>=7.35.1. Plus
Hermes itself states "Only one external provider can be active at a time."
Consequence: we cannot run both, and we cannot "try both and keep the better" on one profile without uninstalling. A spike is still cheap (install, test, remove), but the production choice is a single one. This is the fact the earlier study could not have known, because the catalog did not exist yet.
4. Self-host on LAB — Docker is the real blocker
Measured on LAB just now:
| Check | Result |
|---|---|
which docker | not on PATH |
systemctl is-active docker | inactive |
podman | not installed |
| Postgres binaries | none |
| nothing on :5432, :6333, :8888, :9999 | confirmed |
| RAM / disk | 30 GB (23 GB available) / 361 GB free — ample |
So neither repo's docker compose up path works today. Every quick-start in both
READMEs is Docker-first. That is the honest gap between "self-hostable" and
"self-hostable here".
The Docker-free paths that do exist
| mem0 | hindsight | |
|---|---|---|
| Bare metal | server needs Postgres (no Docker-free server path found) | pip install hindsight-api ✅ documented |
| Embedded DB | — | embedded pg0 ✅ |
| In-process (no server) | ✅ OSS SDK mode (local Qdrant path or PGVector) | ✅ hindsight-all (but see §3 — conflicts) |
| Shared across processes | needs the server (Docker + Postgres) or a Qdrant server | local_external → point at an existing instance |
Two viable Docker-free shapes:
- Install Docker on LAB (one package install) and run either server properly. Simplest, matches how our fleet already reasons about services, and gives a LAN-bound HTTP endpoint.
- hindsight bare-metal —
pip install hindsight-api+ embedded Postgres, no Docker at all. mem0 has no equivalent: its shared-store path wants Postgres.
⚠️ Not verified: whether LAB's Python 3.14.7 satisfies either server's runtime
floor, and whether hindsight-api's embedded Postgres builds cleanly on this host.
Both are install-time discoveries, not reading.
5. "Pulse can connect to it" — the requirement that splits the two
This is where the two candidates genuinely diverge, and it is Young's actual constraint.
Network path: LAB 192.168.4.60, Pulse 192.168.4.34 — same /24. LAB→Pulse
is proven reachable (my A2A probes today). Pulse→LAB is the same subnet, so it should
hold — ⚠️ not independently proven from Pulse's side, and that probe is the first
thing to run before committing to either.
mem0 — built for this
- Its server compose runs
uvicorn main:app --host **0.0.0.0** --port 8000→ LAN-reachable. - The plugin's config table documents the sharing mechanism explicitly:
| Key | Default | Description |
|---|---|---|
user_id | gateway user ID, then hermes-user | "Set a stable ID to share memories across gateways" |
agent_id | hermes | Agent identifier attached to writes |
→ "An explicit user_id other than hermes-user takes precedence… Searches use
that user identity across sessions; writes attach agent_id and metadata.channel."
That is literally the Pulse↔LAB requirement, as a documented config value.
Set one user_id on both hosts and they share one memory pool, with per-agent
attribution preserved on writes.
hindsight — needs a deliberate mode choice
- Its three modes are
cloud,local_embedded,local_external. local_embeddedruns a daemon athttp://localhost:8888— loopback. Pulse could not reach that.local_external= "Connect to an existing Hindsight instance" — which is the correct mode for a LAB-hosted shared server. So the shape is: run the server on LAB bound to the LAN, point Pulse at it vialocal_external.
Net: mem0 shares memory with less ceremony (a user_id string). hindsight needs
the server + local_external wiring. But hindsight's server path is the one that
works without Docker.
6. Security posture (my lane) — before this touches the LAN
A memory server on the LAN is a high-value target: it contains everything every agent has said. Three things I'd require before it is exposed beyond loopback:
- 🔴 mem0 ships anonymous telemetry ON by default.
MEM0_TELEMETRY=truein.env.example, with the compose file defaulting it on, and the requirements listposthog. It sends "a single onboarding event per install (install UUID, email domain, server version, source). No PII" — and the catalog description flags it too. SetMEM0_TELEMETRY=false. Their own README also notes the opt-out. - Auth must stay on. mem0 is "secure by default": dashboard JWT +
X-API-Key,AUTH_DISABLED=falseby default, per-IP rate limiting on auth endpoints (slowapi). ⚠️ ButAUTH_DISABLED=trueis a single env var and is documented as "local development only" — it must not be set on a LAN-bound instance./docs,/redoc,/openapi.jsonare served and explicitly excluded from request logging — the API surface is discoverable by anyone who can reach the port. - Do not expose it on
0.0.0.0beyond the LAN. Both compose files publish ports on the host's external interface. Bind to the LAN interface (or loopback + tailnet/SSH tunnel), and keep it off any public interface. Our prod box already fronts services with nginx/Authelia — that pattern applies if this ever leaves LAB.
One trust observation from our own prior research that bears on both: the 2026-10-11 memory-architecture study established that assistant-authored memories are a contamination vector (fix: speaker-attested grounding — trust user turns, treat peer-agent assertions as lower-trust), and that procedural memory must never be auto-promoted.
🔴 Verified in mem0's OSS source: it does the opposite of our SAG rule
I read the extraction prompt rather than the README, and it is decisive.
1. It extracts from BOTH roles, by design. mem0/configs/prompts.py
(ADDITIVE_EXTRACTION_PROMPT):
"You extract from BOTH user and assistant messages. User messages reveal personal facts… Assistant messages contain recommendations, plans, suggestions, and actionable information the user may later reference."
"## Example 12: Multi-Speaker Conversation — Extract From ALL Speakers"
This is precisely the pattern our study identified as the false-memory mechanism — the one SAG fixes by restricting evidence to user turns (measured +11.94pp false-memory resistance). mem0's OSS pipeline is built to include assistant-authored content, and its own example enshrines "extract from ALL speakers" as a lesson.
Why it bites harder in our fleet than in mem0's target market: mem0 is designed
for one user talking to one assistant. Ours is 11 agents in one shared store,
where a peer agent's message arrives in the assistant/agent role. Under mem0's
prompt, another agent's assertion is first-class extractable memory — the exact
"teammate-sourced assertions are lower-trust" hazard our study named. A
single-user product's defaults are not neutral when applied to a multi-agent store.
2. Dedup is prompt-only, not code. There is no UPDATE or DELETE path
(verified: grep -c 'event.*UPDATE\|event.*DELETE' = 0; ADD-only confirmed at
mem0/memory/main.py). Deduplication is delegated entirely to the LLM:
"## Recently Extracted Memories — Memories already captured from recent messages in this session (up to 20). This is your primary deduplication reference — do not re-extract information already captured here."
A 20-item window is the entire dedup mechanism. That is why our September service accumulated 11 literal duplicate facts with a different implementation — the same structural cause.
3. There is no staleness metadata. grep for written_at, last_confirmed_at,
validity_basis across mem0/ returns nothing. Our study called that metadata
"the mechanism that makes behavior consistent over time." mem0's ADD-only design
has no place to put it.
⚠️ The honest counterweight: this is not a defect for mem0's design goal (personalization for one user, where "assistant recommended X" is genuinely useful context). It becomes a defect in our topology, and it is mitigable — see below.
hindsight — the symmetric check I owed, and it comes out structurally better
I said above that I had read mem0's internals more closely than hindsight's. I went back and read hindsight's retain path so the comparison is even. It is materially different, in the direction that matters.
hindsight's Hermes plugin (hindsight-integrations/hermes/__init__.py) keeps the
speaker as a first-class field, not as prose:
def _build_turn_messages(self, user_content, assistant_content):
return [
{"role": role, "content": f"{prefix}: {content}", "timestamp": now}
for role, prefix, content in (
("user", self._retain_user_prefix, user_content), # default "User"
("assistant", self._retain_assistant_prefix, assistant_content), # default "Assistant"
)
]
Plus per-write metadata: retained_at (UTC audit time), message_count,
turn_index, source, and configurable retain_user_prefix /
retain_assistant_prefix (env HINDSIGHT_RETAIN_USER_PREFIX /
HINDSIGHT_RETAIN_ASSISTANT_PREFIX).
Why that is the better shape for our problem, stated precisely:
| mem0 | hindsight | |
|---|---|---|
| Speaker in the payload | not a field — the prompt is told to extract from both roles | role field per message + prefix |
| Our SAG rule enforced by | a sentence in custom_instructions competing with "extract from ALL speakers" | the label survives into the store, so the reader can filter on it |
| Read-time trust decision | needs agent_id metadata (present) | role + retained_at + turn_index (present) |
⚠️ The precise claim, so I do not overstate it: hindsight preserves the
speaker label; I found no evidence it filters or down-weights by role on the
retain path (grep for role-based trust weighting across hindsight-api/ returned
nothing). So it is not SAG either. The difference is that hindsight hands our
read path the field it needs, where mem0's extraction prompt has already dissolved
the distinction into prose by the time anything is stored.
That is the distinction I would decide on: neither provider implements speaker-attested grounding, but only one of them leaves the evidence intact for us to implement it ourselves.
One more thing worth crediting: hindsight's plugin has a genuine security-shaped
config I did not expect — trusted_project_dirs, used to decide which directory's
.hindsight/config.toml may set the memory bank. That is a trusted-source check on
configuration, which is a class of control mem0's plugin does not have.
Back to mem0 — is it mitigable? Yes, partially
MemoryConfig.custom_instructions (mem0/configs/base.py) is a real field, and
generate_additive_extraction_prompt(..., custom_instructions=...) threads it into
the extraction prompt (mem0/memory/main.py:948). So a deployment can add our SAG
rule as custom instructions ("extract only user-attested facts; treat agent-authored
content as untrusted").
But be honest about the strength of that fix: it is a prompt-level control, not
a structural one. It sits in the same prompt as "extract from BOTH roles" and "extract
from ALL speakers", so it is a conflicting instruction, not a gate — the LLM decides.
Our own study's conclusion is that write-path validation must be structural
(SAG filters at the filter stage, promotion gates on procedures), and a competing
sentence in the same system prompt is not that. I would treat custom_instructions
as harm reduction, not as the security control.
One mitigation that IS structural: mem0's plugin attaches agent_id and
metadata.channel to every write (verified in _backend.py). Because attribution is
per-write, a reader can filter or downgrade agent-authored memories at query time —
which moves the trust decision out of the extraction prompt and into our read path.
That is the right place for it, and it is why §7's read path matters more than the
provider choice.
7. Prior art — we have built this once already, and it went dormant
Find-before-register turned up a real precedent, which changes the framing:
2026-09-28-spec-cross-agent-memory-bus.md(Tam, spec) +2026-09-28-spec-solos-memory-service.md- It ran on LAB: Qdrant at
192.168.4.60:6333,memory_episodicwith 1,548 rows, per-agent attribution (sol406,atlas289,ace182,mira177,min174,alpha146,nova90,echo84), embedder ruled asBAAI/bge-small-en-v1.5. - Its own preflight found the exact defects we are still worried about: 93% of rows were raw turn text, 11 literal duplicate facts, 15.8% of points with no agent attribution at all, and zero live readers — it had been silently archiving for 5 weeks.
Today: nothing is listening on :6333 or :8888. That service is gone.
The lesson is not "mem0 is better than what we built" — it is that we already built a cross-agent memory bus, it accumulated 1,548 rows, nobody read it, and it died quietly. Adopting a catalog provider does not fix that; the read path is the product, and that is what failed last time. Any recommendation must name who reads this memory and in what loop, or we will re-run the same experiment with better marketing.
8. Recommendation
Do not adopt on the strength of the repos. Adopt on the strength of a read path.
Given the evidence, my ranked recommendation:
1. Pilot hindsight first (my recommendation), because:
- MIT with no open-core gating found — the whole product is the licence. mem0's self-host tier is explicitly the reduced one ("Teasers", rerank platform-only).
- It is the only candidate with a documented Docker-free path (
pip install hindsight-api+ embedded Postgres), and Docker is absent on LAB. - Its
local_externalmode is designed for exactly our shape — "connect to an existing instance" — so the LAB-hosted/Pulse-reachable topology is a supported mode, not a workaround. - Benchmarks carry independent reproduction (VT + WaPo), which is a stronger provenance class than mem0's self-reported, explicitly-platform-only numbers.
- It is more actively developed (last commit the day of this study).
- Its "reflect" operation and knowledge graph are aimed at consolidation, not just accumulation — the layer mem0's ADD-only store explicitly lacks (§6).
2. Keep mem0 as the fallback spike, because it wins on one axis that matters:
user_idsharing across gateways is a documented one-value config — the Pulse↔LAB requirement with the least ceremony.- It is far smaller and simpler to operate (1,828 files vs 5,259).
- But its shared-store path needs Docker + Postgres, its self-host tier is the
gated one, and its extraction prompt is built to ingest assistant/agent-authored
content as first-class memory (§6) — the exact hazard our own study identified.
If we do run mem0,
custom_instructions+ query-timeagent_idfiltering are mandatory, not optional.
3. Before either: install Docker on LAB (or commit to hindsight's bare-metal path). This is the actual blocker, and it is one package install — not a study item.
4. Sequence I would propose:
| # | Step | Why |
|---|---|---|
| 1 | Prove Pulse→LAB reachability (the reverse of my earlier probe) | The whole goal depends on it; unproven today |
| 2 | Decide the read path — who queries this memory, in what loop, and what happens if nobody does | §7: this is what killed the last attempt |
| 3 | Install Docker (or pick hindsight bare-metal) | Removes the only hard blocker |
| 4 | Install one provider, LAN-bound, telemetry off, auth on | §3: they cannot coexist |
| 5 | Set the trust rule before the first write (user-attested vs agent-authored) | §6: mem0 defaults to ingesting agent content; the read path is where we can still gate it |
| 6 | Spike 2–3 real sessions on one agent, then measure whether recall actually changed an answer | Vendor benchmarks are their claims; ours must be ours |
Do not install both, and do not enable it fleet-wide before the read path is named — that is the precise failure mode we already paid for in September.
9. Not verified (read as limits, not findings)
- I did not install or run either provider. No
hermes plugins installwas executed, no memory was written, no recall was measured. Every claim above is from source, config and live host probes. - Pulse→LAB reachability is inferred from the shared /24 and my LAB→Pulse probe — not proven from Pulse's side. Step 1 of the sequence.
- Both repos were cloned
--depth 1, so the catalog's pinned SHAs (43849c6e,d56c4acd) are not present in my clones; I confirmed the pins match the catalog and the plugin versions (1.3.0,1.2.3), not the pinned commits. - No benchmark was reproduced. mem0's 92.5/94.4 and hindsight's LongMemEval SOTA are their claims; mem0's is explicitly the managed platform's.
- mem0's extraction behaviour IS verified from source (§6: both-roles extraction,
prompt-only dedup, no staleness metadata) — but I read the prompt and config, not
a live extraction run. Whether a real deployment's LLM obeys or overrides
custom_instructionsis unmeasured, which is exactly why I do not treat it as a security control. - I did not read hindsight's extraction/retain pipeline at the same depth as
mem0's. Its "reflect" and knowledge-graph claims are from its README and mode
descriptions, not from its prompt source. This is an asymmetry in my own
evidence — I read mem0's internals closely and hindsight's less so, so the
comparison in §6 is uneven in a direction that flatters hindsight. Anyone deciding
on that section should know it.
Update — partially closed. I went back and read hindsight's retain path (_build_turn_messages, metadata, speaker prefixes) and confirmed the speaker is a first-classrolefield withretained_at/turn_indexmetadata (§6). That resolves the retain-side asymmetry. Still unread on hindsight's side: its server-side extraction/consolidation prompts (what its API does with a retained item after it arrives). I read the Hermes plugin's retain path, not the server's pipeline. So the asymmetry is narrower, not gone — and it still points the same way. - hindsight's
local_embeddedbind address — I found the default URL (http://localhost:8888) but not the daemon's bind interface in the plugin source. Whether it could be bound to the LAN is unconfirmed;local_externalis the mode I would use regardless. - Cost was not measured. Both need an LLM (and mem0 an embedder) per write; our
free opencode gateway is OpenAI-compatible and hindsight explicitly supports
openai_compatiblewithllm_base_url, but I ran no billable or free-model call to price a real workload. - I did not check whether either plugin's tests pass on our Hermes version.
✅ CLOSED 2026-10-21 (Sol, card
t_ac60925f) — the Docker blocker is resolvedEcho's §4 and §8 step 3 both said: "install Docker on LAB (or commit to hindsight's bare-metal path)" — the one hard blocker. Both "not verified" caveats above are now measured, and the answer is the bare-metal path:
- Docker is NOT installable on LAB by an agent. No root (
sudoneeds a password,SUDO_PASSWORDis not set in the profile.env), and AppArmor denies the user namespace rootless containers need (apparmor="DENIED" ... capability=sys_adminonunshare -Ur). Installing it is now one command Young runs, or one env var — it is a permissions decision, not a study item.- hindsight's bare-metal path WORKS on LAB —
hindsight-api-slim 1.0.0+pg0-embedded 0.15.2(PostgreSQL 18.1.0) + ONNX embeddings, installed as thelabuser with no root and no container runtime. Health, retain and recall all exercised over192.168.4.60:8888(the LAN bind Echo flagged as unconfirmed — it binds fine). LAB's Python 3.14.7 satisfies the runtime floor (Requires-Python: >=3.11), and the embedded Postgres builds cleanly on this host. Both of Echo's "not verified" items are closed, positively.- One install trap worth knowing:
hindsight-api[embedded-db]resolves tohindsight-api-slim[all], which drags intorch→CUDA (~1.5 GB, and it failed on this host). Install the slim package with only[embedded-db]+[local-onnx]. Also: the defaultembeddings_provider=localandreranker_provider=localboth wantsentence-transformers(→ torch) and fail at startup; useonnx+rrf. (reranker_provider=noneis not valid despite appearing in hindsight's own warning text — the value isrrf.)- Embeddings, specifically: our
opencode-gogateway serves 38 chat models and zero embedding models, and its key is rejected byapi.openai.com. So a remote embedding endpoint is not available to us — ONNX is the only working embeddings path, and it needs no key at all.Full decision note, with the evidence:
[lab-container-runtime-bare-metal-2026-10-21](lab-container-runtime-bare-metal-2026-10-21)(Docs/Fleet/03-decisions/lab-container-runtime-bare-metal-2026-10-21.md)What this does NOT change: the provider recommendation (still hindsight over mem0), the mutual-exclusion finding (§3), the SAG/security findings (§6), and §7's lesson that the read path is the product —
t_3841e128(Min) is still the real blocker, not Docker.
10. Review + verification pass (tam, 2026-10-20) — step-1 gap CLOSED live
Echo owns the analysis; this section is my verification record + the one gap I could close from the Pulse side tonight.
10.1 — Pulse→LAB reachability: PROVEN from Pulse side (her step 1, now done)
I probe Pulse→LAB live TONIGHT (laptop mesh tunnels 18301/18305/18313 → LAB agents), real LAB-v3 SendMessage calls with the A2A-Version 1.0 header:
- 18301 →
TASK_STATE_COMPLETED✅ - 18305 →
TASK_STATE_COMPLETED✅ (mira-plane) - 18313 →
TASK_STATE_COMPLETED✅ (sol-plane)
All three LAB agent lanes reached from Pulse in one pass. The /24 inference is now a measured fact. Echos sequence step 1 is CLOSED — her constraint table can adopt
✅ DECIDED 2026-10-21 (Sol, card
t_af604d1b) — hindsight, not mem0The provider choice is now a decision of record:
[memory-provider-hindsight-2026-10-21](memory-provider-hindsight-2026-10-21)(Docs/Fleet/03-decisions/memory-provider-hindsight-2026-10-21.md)hindsight runs. Rejected on three measured grounds: mem0's self-host tier is the reduced one ("rerank is platform-only",
_backend.py:94), its extraction prompt is built to ingest both roles ("Extract From ALL Speakers",prompts.py:886) — the exact false-memory mechanism our own 2026-10-11 study identified — and its telemetry is on by default (telemetry.py:14). hindsight keeps the speaker as a first-classrolefield (__init__.py:1684), so our read path can implement speaker-attested grounding itself.⚠️ One correction to this study's §3 — the exclusivity mechanism. The card was migrated here saying "they cannot coexist — protobuf conflict." The protobuf conflict is real, but it is not what makes them mutually exclusive.
- What actually binds: Hermes' own exclusive-provider rule.
kind: exclusive(hermes_cli/plugins_manifest.py:270), enforced atagent/memory_manager.py:434— "Only one external memory provider is allowed at a time." Onememory.provider:value. This binds before any dependency resolves.- What the protobuf conflict actually binds: the server layer.
mem0aipinsprotobuf<7.0.0;hindsight-api-slimneedsprotobuf>=7.35.1— unsatisfiable. But the thin plugins pull no protobuf between them, and I installed both thin plugin dependency sets into one venv on LAB successfully (protobuf 6.33.6 · mem0ai 2.2.1 · hindsight-client 0.10.3 · hindsight-embed 0.10.3). The conflict bites when you try to run the full hindsight server in a venv that already carriesmem0ai.- The decision is unchanged. The stated mechanism was wrong, and this study's §3 should not be cited as the reason.
Also corrected: the catalog pin. The live catalog has hindsight at 1.2.3 @
d952b6e6; the on-diskplugin-catalog/hindsight.yamlstill says 1.2.1 @d56c4acd(stale local copy —hermes plugins searchshows the live value). The mem0 pin43849c6ematches the live catalog but that commit no longer resolves on GitHub.Install path (settles the Docker question):
pip install hindsight-api-slim[embedded-db,local-onnx]— bare-metal, no root, no container runtime — embedded PG 18.1.0, ONNX embeddings, and theopencode-goprovider built in with our gateway as its default base URL. Re-proven live on LAB today: health, retain and recall over192.168.4.60:8888.What this does NOT change: §6's SAG/security findings, §7's lesson that the read path is the product, and §8's sequence — the read path is still the gate (
[memory-read-path-2026-10-21](memory-read-path-2026-10-21): metricrecalls_with_results, unmeasurable today).
Next.js Commerce + Medusa ecosystem study (2026-10-13)
All repo stats pulled live from the GitHub API on 2026-10-13; blog + docs pages fetched live. Extends saleor-study (technical half) into the Medusa stack and the extension/auth model.
The READ path for agent memory
Card t_3841e128 asks four questions before any provider is switched on. This note answers all four from live probes, then names the one metric. The honest headline is uncomfortable and is stated up front:

