Aegis ships across the whole Sibyl Memory plugin family at once: client, CLI, Hermes adapter, MCP server, and the first public release of a LangGraph adapter. It closes a 35-finding hardening pass, a 10-lens adversarial audit run against the current tree and adjudicated finding by finding, spanning reliability, multi-tenant correctness, privacy, and security.
Here's the honest frame. Most of this release is defense-in-depth. No API changes. No config changes. If you already run Sibyl Memory, you get every fix in this list for free on upgrade.
Why this matters
A demo doesn't find these bugs. Production does.
Running an agent in production means memory has to survive things a quick test never exercises: a process that spins up a fresh thread per turn and never closes the connection it opened, two writers touching the same cache file at once, a crash landing mid schema-migration. None of that shows on day one. It shows up after days of real load, and the failure is usually silent: a search index that quietly returns nothing forever, a connection that's already closed from another thread and raises instead of reconnecting, a tenant field that's present but empty and routes an account's memory into a shared bucket instead of its own.
Aegis targets exactly that class of bug: not "does it work," but "does it keep working, correctly, under concurrency, across a crash, at scale, for the account it's supposed to serve."
The hardening, by theme
Reliability and durability. The client tracked every per-thread SQLite connection in a plain list, pruned only at shutdown. A long-lived process opening one thread per turn, Hermes's actual pattern, accumulated connections until it hit EMFILE, at which point writes started failing silently. Connections are now tracked as thread-weakref pairs, swept on every registration, with liveness-probing on reuse. Separately, the old FTS5 migration ran as three separately-committed steps with no completion marker: a crash between the drop and the rebuild left a v3-shaped but empty search index that read as "already migrated," so search returned nothing forever. The rebuild now stamps its version marker in the same transaction as the rebuild itself. And a failed COMMIT, not just a failed pre-commit step, used to leave a connection stuck mid-transaction for the rest of a session; it now rolls back before re-raising.
Multi-tenant correctness. Before this release, tenant resolution diverged across surfaces. The CLI's credentials write didn't persist the server-issued tenant_id at all. MCP and Hermes fell to the shared DEFAULT_TENANT bucket whenever tenant_id was missing or present but empty. The unreleased LangGraph adapter didn't resolve identity at all. A malformed or legacy credentials file could silently route an activated account's memory into the shared default bucket. Every surface now resolves identity through one ladder: tenant_id -> account_id -> DEFAULT_TENANT, reaching the default only when credentials are genuinely absent, never when a field is merely empty.
Privacy on the hosted path. These narrow what the Sibyl-routed summarizer can ever see; the BYOK path is unaffected. Dict key names used to leak verbatim into the redaction shape sent upstream, so content could hide in a key name as easily as a value; keys are now reduced to length-only shape descriptors. Hint redaction was a four-field denylist, meaning any future field leaked by default; it's now an allowlist of known pure-shape fields, everything else stubbed. And the usage heartbeat's bearer token, previously sent to any env-overridden URL, is now attached only when the resolved host is sibyllabs.org or a subdomain, checked by real hostname parsing, not string matching.
Security. FTS5 search queries had no length ceiling: a multi-megabyte query could expand into a few-hundred-thousand-term MATCH across four tiers, a CPU and memory DoS reachable from the client, MCP, and Hermes alike. Queries now truncate to 4096 characters before tokenization. A symlink guard on the cache path was dead code, resolving the path before ever checking if it was a symlink; it now checks first, and SQLite's WAL/SHM sidecar files get the same guard, previously absent entirely. And sibyl logout now revokes the server-side bearer instead of only unlinking local credentials, so a stolen token doesn't stay valid indefinitely.
The LangGraph adapter
sibyl-memory-langgraph is the first public release of SibylStore, a LangGraph BaseStore backed by the same local SQLite and FTS5 engine as every other surface:
from sibyl_memory_langgraph import SibylStore from langgraph.graph import StateGraph store = SibylStore() # ~/.sibyl-memory/memory.db, free tier graph = StateGraph(State, store=store)
It's a long-term store, not a checkpointer and not a vector store. search is lexical FTS5, not embedding similarity. There's no vector index involved, and PutOp.index / PutOp.ttl are accepted and ignored.
Because this is a first release, the audit's LangGraph-relevant findings were fixed before publish, not patched after the fact: search issues one MATCH across categories instead of fanning out per category, pagination clamps instead of crashing on limit=None or a negative limit, filter operators degrade to "no match" instead of raising on an incomparable operand, and batch validates every operation in a batch before executing any of them. SibylStore() also reads credentials.json and resolves tenant identity through the same ladder as every other surface, so it ships with zero identity blind spots.
What this enables
One memory engine, every framework. Sibyl Memory is now usable natively from LangGraph in addition to Claude Code, Codex, Cursor, Hermes, and any MCP-compliant runtime, all backed by the same durable storage and the same tenant model. A team running one shared install across many accounts doesn't have to worry about a malformed credentials file quietly merging their memory. What leaves the device on the hosted path is allowlisted shape metadata, not whatever a denylist forgot to name. A mid-migration crash, a concurrent writer, or a failed commit no longer leaves the database in a state that fails silently later.
Versions and upgrading
| Package | Version |
|---|---|
sibyl-memory-client | 0.4.19 |
sibyl-memory-cli | 0.3.19 |
sibyl-memory-hermes | 0.3.13 |
sibyl-memory-mcp | 0.1.12 |
sibyl-memory-langgraph | 0.1.0 (first release) |
| Fresh install | pip install -U sibyl-memory-cli |
| Already installed | sibyl update --apply (not sibyl upgrade, that's the billing flow) |
| New to LangGraph | pip install sibyl-memory-langgraph |
| Source | github.com/Sibyl-Labs/Sibyl-Memory |
Verification
An independent adversarial multi-surface suite, run alongside all five package test suites, put 1,005 tests through and passed 1,005, zero failures. Five additional LangGraph tests are marked xfail by design: documented scope limits, not defects.