Multi-database release. One memora process now serves every workspace from its
own store, with per-database health, images and identity.
Multi-database routing
MEMORA_DATABASESregisters named stores ({name: uri}); a workspace reaches its own at/mcp/<name>. Unset keeps single-store behaviour.- Names are one URL path segment, matched on component boundaries; an unknown store gets a generic 404 that does not disclose the registry.
- A malformed registry, a duplicate name, an empty URI or an unusable backend is fatal at startup rather than silently serving the wrong store.
memory_identityreports which database the session is bound to (#997).
Health and readiness
GET /healthis liveness with no database I/O — the only signal a supervisor may restart on.GET /health/dbis per-database readiness,GET /health/db/{name}a single store.- Probes run off the event loop, bounded and concurrent; a timed-out probe is truly abandoned rather than left to land later.
- Readiness refreshes on its own schedule (
MEMORA_HEALTH_REFRESH_INTERVAL), so a proxy deployment with no loopback caller no longer reportsunknownwhile every database is fine. - Detailed bodies are token-gated (
MEMORA_HEALTH_TOKEN); an unauthenticated caller sees aggregate status only, because FastMCP custom routes are unauthenticated even when MCP auth is configured. - A staleness budget bounds how old a cached result may be before it stops counting as ready.
- A watchdog supervises the shared container (#987).
Session and transport hardening (#999)
- A hard ceiling on live sessions, counted atomically, with admission refunded when a request is rejected — a rejected request no longer costs a session.
- Routing mirrors the SDK's own acceptance rules and the transport's security settings, closing a POST bypass that reached deployments unguarded.
- Terminated transports are purged rather than ignored; idle sessions are reaped.
Images
- Object keys are namespaced per database, so two stores cannot collide in one bucket (#965 phase 3).
- Images are keyed by
(name, uri)rather than name alone — the same name at a new URI is a new image, not a stale hit.
Absorb
- The corpus is cached across calls, keyed on a monotonic database epoch, and loaded once per call instead of once per fact. Absorb of many facts no longer re-reads the store for each one.
Tool profiles (#981)
MEMORA_TOOL_PROFILEexposesfull(43 tools),leader(19) oragent(12). An unknown value refuses to start rather than guessing.- Gating is attested through the public handler path and fails closed if the profile cannot be verified.
Deployment
- Every runtime call routes through
CONTAINER_BIN, not justrun(#996). - Routing is instance-owned; a credential file can no longer supply it.
Docs
- Four version-stamped release-notes files consolidated into this CHANGELOG, which has a stable name README and issues can link to without rotting (#1000).
- README rewritten around the container path, which is what a running memora actually is.