Architecture
Architecture
Product boundary
memoree is a local knowledge appliance, not an agent runtime. It owns artifact lifecycle, memory assertions, context selection, retrieval, and context construction. It is designed for any shell-capable model to use through the same JSON CLI contract; cross-model conformance results have not been published yet.
The first release has one trust domain: the local user. There are no accounts, grants, tenant tokens, or authorization policies. The recommended/default Unix transport uses an owner-private runtime directory and mode-0600 socket. TCP loopback limits exposure to the host but not to the user: another local OS user/process can connect. It is appropriate only for a trusted single-user host or an independently enforced boundary. Non-loopback listeners require the conspicuous --dangerously-allow-non-loopback-tcp process flag. The bundled loopback-published Compose profile has the same single-user-host assumption.
Runtime shape
One Rust binary provides the CLI and daemon. The CLI resolves client-local ambient settings and attaches the selected context to protocol requests. The daemon is the single writer and owns:
- SQLite metadata, immutable revision records, claims, relations, audit data, and the FTS5 index.
- A Git-style filesystem content-addressed store (CAS) for artifact bytes.
- Consumption and echoing of the attached context, plus retrieval-horizon enforcement. Scoped storage and retrieval paths validate context before use.
- The JSON request/response protocol.
The CLI probes daemon version, schema, and lifecycle ownership before ordinary requests. Installer reconciliation may replace only the default daemon it owns (plus the explicitly observed one-time v0.2 legacy case); direct serve and explicit endpoints remain supervisor-owned.
SQLite is authoritative for durable memory. The CAS is immutable. FTS/vector rows are derived projections that can be rebuilt. The CLI-owned project source index is a second, explicitly disposable projection of the Git working tree; it shares no authority rows with memory and cannot create claims automatically.
Every authority schema migration is serialized under a private lock. Before any older store becomes schema 5, Memoree checks available space and atomically publishes a verified old-schema SQLite/CAS recovery snapshot. The migration then rebuilds deterministic projections and verifies SQLite, foreign keys, and projection coverage before commit. Upgrade state records the prior daemon state and phase so interruption cannot turn a previously running installation into a silently stopped one.
Running one process avoids separate Postgres, object-store, and search-server memory footprints. Docker Compose is packaging rather than an architectural dependency; the same binary can run directly on the host.
General model reasoning and tool execution remain outside the daemon. A caller can request one scoped, byte-bounded context bundle and pass it to any companion or model under that caller’s own policy. The CLI additionally provides one bounded adapter, memoree remember, that invokes a selected authenticated Codex or Claude CLI solely to compile natural language into a strict claim proposal. The daemon never receives model-provider credentials, launches a model, or executes generated output.
Ambient context
The normal caller does not send a project or scope on every request. The local CLI resolves ambient context in deterministic precedence order before contacting the daemon:
- Explicit context in the request, intended for controlled integrations rather than routine model use.
- A process-local session context inherited through
MEMOREE_CONTEXT. - The nearest ancestor project marker (
.memoree.toml). - An explicitly configured personal fallback.
- Otherwise, a context-dependent operation fails with
NO_AMBIENT_CONTEXT.
A resolved context contains stable workspace and project identifiers, an optional task identifier and component, and explicit pinned artifacts. Identifiers are not inferred from a mutable directory basename.
Task selection remains process-local. An agent launched under memoree session exec inherits a validated context document through MEMOREE_CONTEXT; it does not change a machine-global “active task” setting that could race with another agent.
Every successful response to a context-dependent operation echoes the resolved context, where it came from, the effective horizon, and whether search was broadened. This makes accidental context drift visible to the caller and audit tooling. Current error envelopes do not repeat resolved context.
Retrieval horizons
Location and retrieval breadth are separate concepts. The v1 horizons are:
ambient: the current task/project plus explicit pins. This is always the default.workspace: an explicit one-request retrieval across the current workspace.personal: an explicit one-request retrieval across all local personal memory.
Settings cannot persist workspace or personal as the default horizon. A broad request must include a reason. An empty ambient result may return a structured hint, but the service does not automatically inspect or search a broader horizon.
An exact lookup by stable artifact or claim identifier is not a search and can resolve the requested object directly.
Exact lookup and pins are read visibility, not write authority. Revisions, tombstones/retractions, and both endpoints of a new relation must belong to the ambient project/task. The service rejects a mismatch as SCOPE_VIOLATION before creating an event or applying relation lifecycle effects.
Graph inspection uses relation.list, a bounded one-hop adjacency read with direction/type filters and an exclusive commit-sequence cursor. Relation rows are independently filtered to the selected horizon. A pin can make a foreign artifact a valid anchor for an ambient request, but does not reveal that artifact’s foreign graph; workspace or personal traversal remains an explicit broadened request with a reason.
Bounded recency
Lexical relevance selects and freezes the top-K candidate membership first. The deterministic bounded_recency_v1 policy then adds a small, type-aware freshness bonus and may promote an eligible item by no more than two positions. The response retains lexical score/position, bonus, final position, effective timestamp and basis, evaluation instant, decay class, eligibility, and policy version so the adjustment is inspectable.
Only current, non-terminal revisions at or before the evaluation instant are eligible; this includes a current conflicted claim so both sides remain retrievable. Artifact freshness uses immutable revision creation time; claims use valid_from when present and otherwise immutable revision creation time. Historical, superseded, retracted, forgotten, and future material receives no bonus. Decision and constraint classes decay slowly with small maximum bonuses; ephemeral observations can decay faster with a larger—but still bounded—bonus.
Recency is enabled by default for recall/search/context requests and can be disabled per request. It never changes the lexical candidate set, retrieval horizon, temporal/currentness filtering, or contradiction lifecycle. Newer evidence is not automatically more correct.
Model boundary
memory.retrieve is the default agent-facing knowledge check. It first projects the same authority-filtered snapshot as memory.recall. Claims carry immutable evidence spans and open contradiction IDs; presence is derived only from deterministic qualification and distinguishes claims, artifact-only material, and no qualified match without asserting truth or broadening scope.
Only after qualified absence may retrieve run one same-horizon candidate probe and return a bounded exact-evidence packet. It admits bytes only from evidence locators attached to candidate claims, never raw artifact or semantic-window candidates, and labels them unqualified. Explicit current/post-migration intent suppresses dated candidate hydration and routes to current source instead. This reduces protocol round trips without allowing candidate similarity to become authority. memory.recall, memory.probe, and citation.get remain independently available for diagnostics and older-client fallback.
When conservative qualification misses a paraphrase, memory.probe is one explicit, same-horizon recovery step using at most one audited meaning-preserving reformulation. It exposes at most eight untrusted titles and provenance-labeled exact source arrays, with claim-backed groups ranked before a two-slot raw-artifact floor. Claim and raw candidates from the same artifact remain separate leads so neither can donate relevance or evidence to the other. Legacy claim evidence is split by a fixed clause policy and resolved only within its cited immutable revision to at most three non-overlapping, hash-verified windows. From the same pinned project scope, the consuming agent fetches the highest-ranked ranged lead first, then up to two title-selected leads only as needed, bounded to nine refs/12 KiB. It issues one refined qualified recall and requires exact entity, predicate-role, state, and facet coverage against the original question. Probe titles and fetched bytes prove only that source material exists; neither can enter context.build or qualify an answer.
SQLite authority and exact lexical/trigram tiers remain sufficient on their own. An explicitly installed Snowflake Arctic Embed S projection can add private contextual candidate windows: bounded source metadata is embedded beside exact artifact passage bytes, while claim type/component is embedded beside the exact statement. Cosine never qualifies an answer. The separately installed TinyBERT-L2 cross-encoder may order only a diversified union of the top eight fused and top eight dense non-exact claim candidates inside each qualification tier. It never touches exact-tier order, artifact/mixed surfaces, qualification, scope, lifecycle, or citations. Model bytes are revision/digest pinned, installed deliberately, warmed before queries, and never downloaded by a retrieval call. Missing/error/slow ordering fails open to the deterministic fused order.
Query analysis records explicit intent hints, identifier density, and a Unicode script profile. Those fields can help a caller choose memory versus current source, but do not translate a query or claim cross-lingual model quality. No language profile changes qualification or authority.
An experimental current-code surface, memoree project map, searches a native pinned Tree-sitter symbol/edge projection plus FTS5 and returns at most eight leads/12 KiB. Every included excerpt and related-symbol citation is checked against the live full-file hash; duplicate targets remain explicitly ambiguous, parser failures degrade per file, and derived edges never become durable memory. project get expands one citation after verifying the live hash. Indexing is explicit by default; on-search reconciliation and continuous watching are opt-in. Watching requires an explicit foreground process and remains single-worker, locked, debounced, adaptively polled, budgeted, and tolerant of transient Git snapshot errors. The canonical skill does not route agents through this surface: matched downstream evaluations did not show a net benefit. Repository tools remain authoritative for current code, and current bytes override dated memory.
Optional operational metrics form a fourth, non-authoritative local store beside authority, semantic projections, and the project index. Consent and bounds live in an atomic owner-private project-ID-keyed settings file outside the repository, so each collaborator opts in independently and the shared marker remains backward-compatible. Event rows live in a separately permissioned, size-capped, retention-pruned SQLite database under the application data directory. Its closed schema contains no source or query text and its writes are best-effort, so observability cannot make retrieval fail or change ranking. Explicit randomized experiment observations share that disposable database but are exempt from event retention and never infer controls from passive events.
Schema 5 also accepts adapter-produced summaries, aliases, entities, and hypothetical questions as cited derived projections. Each projection is bound to one immutable artifact revision and at least one exact raw byte span. It can add an artifact to the unqualified candidate pool, but cannot qualify presence, become claim evidence, or enter context.build by itself. Returned excerpts are the exact authority bytes, never the derived text.
External systems synchronize through a connector-neutral source contract. Adapters remain separate processes and keep their credentials: they register source identity, ingest stable external id/revision pairs, and checkpoint cursors and health. Replaying identical bytes is a no-op; reusing an external revision for different bytes fails closed. Upstream removal calls source.withdraw, which excludes the artifact and its projections from future retrieval but deliberately performs no CAS or backup erasure.
memoree checkpoint is also caller-side. It stores one private, bounded, last-write-wins continuity note per session under a pending directory that the daemon, database, CAS, search index, recall, and context builder never inspect. Review and compiler preview remain local; only explicit memoree pending apply crosses the normal remember write boundary. This prevents lifecycle capture from becoming background self-mutation or artifact-only retrieval noise.
context.build is the explicit handoff from memory to an external reasoning system. It freezes the retrieval result, labels excerpts as untrusted, preserves exact citations, reports conflicts and truncation, and stays within the caller’s byte budget. Ambient retrieval is the default; wider horizons still require a reason.
memoree remember is a narrow caller-side exception to manual orchestration, not a daemon operation or general agent loop. The CLI resolves and freezes ambient scope before inference, validates a private persisted provider/model choice against model data requested from the authenticated CLI, and runs one ephemeral low-effort schema-constrained call with tools and session persistence disabled. Codex additionally disables web search, user configuration, rules, hooks, apps, memories, and multi-agent behavior; Claude uses safe mode with an empty tool set. The compiler returns only typed statements and exact source quotes. Rust enforces bounds, rejects unknown fields, duplicate statements, missing quotes, and non-unique quotes, then computes byte spans itself. Preview is the default; only --apply submits ordinary idempotent artifact and claim mutations. A compiler or authentication failure performs no write; raw preservation requires an intentional --raw --apply invocation.
The default subprocess environment exposes only the small set of home/config, path, locale, and temporary-directory variables needed for cached ChatGPT or claude.ai login, while excluding API keys and access tokens. API-key auth is a Codex-only per-invocation fallback available only through explicit --allow-api-key; callers must ask the human before enabling it. Even then, the key is supplied to codex exec, not used by a direct API implementation.
This boundary intentionally denies the model authority over context, retrieval horizon, artifact identity, confidence, relations, conflicts, lifecycle changes, deletion, and write intent. --raw bypasses inference entirely. Other reasoning still belongs to the consuming companion, and model output is never itself a protocol request.
Contradiction edges remain immutable, while schema-v3 conflict_cases are stable-ID assessments that each freeze two exact claim revisions and retain their lifecycle (open, stale, or resolved). Every lifecycle change has an immutable conflict_events record. Claim revision atomically stales the old case and opens a new assessment over both current non-terminal endpoints for every still-live contradiction relation; a partial unique index enforces at most one open case per relation. Retraction and supersession resolve affected open cases, then non-terminal claim presentation is recomputed from surviving current cases. conflict.list exposes bounded ambient/workspace/personal views with frozen/current snapshots and a case-sequence cursor so a model can propose reconciliation without rewriting history. Schema-v1 stores reconstruct the relation-time assessment from immutable commit sequences and add a current case when drift occurred; schema-v2 heads become preserved cases and receive the same live reassessment. Neither migration rewrites logical claims, revisions, relations, events, or commit_seq.
Knowledge model
Blob
Immutable bytes addressed by a BLAKE3 digest. Multiple revisions or artifacts can reuse one blob.
Artifact
A stable logical identity representing evidence or a produced object: a document, log, command result, decision record, image, PDF, or other file. Content changes create immutable revisions; they do not mutate historical bytes.
Claim
An atomic fact, decision, constraint, preference, procedure, or observation. A claim has immutable revisions, lifecycle status, and temporal validity where relevant. Evidence locators can cite a complete artifact revision or an exact byte range for passage-specific evidence; evidence itself is optional when the assertion has no source artifact. Exact claim history is a globally readable, newest-first paginated lineage. Its revision fields are historical, while lifecycle fields on every page item reflect the logical claim’s current state.
Relation
An explicit derived_from, supports, contradicts, supersedes, references, or duplicates edge between artifacts and claims. For supersedes, the source is the new/current entity and the target is the older entity. A contradiction is retained and surfaced; it is not resolved by silently overwriting one side. Relation rows are immutable history; callers inspect endpoint lifecycle separately, and treat edge metadata as untrusted reference data.
Chunk
The lexical projection keeps private exact artifact chunks and immutable byte offsets for long content; the semantic projection uses overlapping, bounded windows no larger than 384 bytes. Projection identities never escape as authority. Search excerpts always cite a stable artifact/claim revision and, when derived from an artifact body span, the exact [start_byte, end_byte) bytes. Title-only matches reset to the revision citation rather than retaining a stale body span. Durable evidence locators remain exact artifact-revision spans, so rebuilding any projection cannot invalidate stored claims.
Recall result
A deterministic claim-first read for “does memory have something about this?” It returns current or disputed claims with exact evidence revisions and byte spans, open contradiction summaries, and a separate bounded list of raw artifact references. Up to five per-type unqualified_candidate suggestions may expose useful near-matches from the same snapshot without affecting presence; they carry exact citations but are not remembered facts. Recall never generates prose, assigns truth confidence, searches history, or broadens the horizon.
Context bundle
An ephemeral, byte-bounded selection of excerpts for model input. It includes a manifest, revision-stable citations, rendered claim evidence refs, inclusion reasons, byte-budget omission counts, retrieval-truncation metadata, and unresolved conflicts. Rendered source lines are kept inside explicitly labelled Markdown blockquotes so artifact headings and role-like text remain visually subordinate to the trust warning. The manifest also reports deterministic risk_signals for common instruction-override, role-spoofing, tool-execution, and sensitive-data language. Signals are explainable warnings, not a safety classifier: their absence never makes content trusted. These defenses reinforce, but do not replace, the content_is_untrusted boundary. omitted_count covers only candidates excluded by max_bytes; retrieval_truncated separately reports candidates beyond the search limit. Retrieved content is evidence, not executable instruction.
Mutation and read consistency
All logical mutations accept an idempotency key. Repeating the identical request with the same key returns the original outcome; reusing that key with different input is an IDEMPOTENCY_CONFLICT.
Artifact and claim revisions require the current revision identifier. A stale if_revision fails with REVISION_CONFLICT rather than dropping a concurrent update.
Current-only claim search evaluates the half-open validity interval [valid_from, valid_until) at one instant per request. Future and expired claims are excluded unless include_historical is explicit; historical claim hits expose that evaluation and revision currentness in provenance.
Successful mutations return a monotonic commit_seq. A dependent search or context-build call can pass that number as min_commit_seq. The service must either make the index observe that commit or return INDEX_NOT_READY; it must never silently return an older view while claiming the bound was met.
Forgetting first tombstones the logical object. Physical garbage collection is separate because a blob may still be referenced by another revision, artifact, backup, or audit record.
Storage now and later
The implemented default is SQLite plus filesystem CAS. It is the lowest-resource configuration and remains the reference behavior.
The non-streaming v0.1 protocol deliberately caps raw artifacts at 8 MiB, encoded content at 12 MiB, frames at 24 MiB, and concurrent connections at four. Those bounds contain JSON/base64 amplification while preserving a useful local artifact size; future streaming support must be measured before these limits are raised.
The storage boundary is intended to admit a generic S3-compatible blob adapter later. SeaweedFS is a good optional local implementation because it can expose S3 from a compact all-in-one process, as demonstrated by the referenced IU LMS development stack. That adapter and profile are not implemented in this repository yet.
When added, SeaweedFS should remain opt-in and non-authoritative. A usable profile must include deterministic credentials, idempotent bucket creation, authenticated put/get/delete readiness checks, disk-headroom reporting, and backups that pair a database checkpoint with a blob manifest at the same commit sequence. Merely seeing a healthy SeaweedFS process is not sufficient.
Postgres and external search remain deferred. Local semantic embeddings and ordering-only reranking are optional, pinned projections admitted only behind evidence-first boundaries: authority filtering precedes model work, exact qualification remains deterministic, context bundles stay qualified-only, and resource/quality promotion gates are evaluated separately.