Agent Memory
Get started

Architecture

One service between the agents and the store.

Agents speak only to this service, and the service is the only database user, reader and writer. Nothing about the query language, tenancy or indexes reaches an agent: an agent knows a set of methods and nothing else.

The store is invisible

Exactly one writer, so the promises can be kept.

That is not tidiness, it is what makes the promises true. A maintained updated_at exists only if exactly one writer maintains it, and the same decision keeps a pre-1.0 store's risks inside one component and the backend replaceable.

The store is TessariDB. The service declares the tables and indexes it writes on every call, so a node that has never seen it is ready on the first one.

One contract

MCP, REST and a command line, rendered from one schema.

The schema is the source: tool definitions, the OpenAPI document and the CLI flags are generated from it, so a behaviour cannot exist on one surface and not another. Input is validated and refused by name; output has one declared envelope.

An agent from a framework nobody here has seen should be able to learn the whole thing from the tool descriptions alone. What a description cannot say — what the service is for, and which of two overlapping verbs to reach for — is sent once in the MCP handshake's instructions.

The three surfaces
SurfaceForHow it is reached
MCPagents, as a native tool surfaceover HTTP at /mcp, or as a child process over standard input
RESTservices and the future interfaceAuthorization: Bearer on each request
CLIpeople and scriptstessari-am <verb>; administration lives behind tessari-am admin

Answers

Refusals name the field and the fix. Hints teach the workflow.

Every verb answers in one envelope: the result, what was written with its version, and hints. A refusal carries a code, the field it is about and what to do instead. The three answers are kept apart on purpose — a refusal, an unavailable plane that is retryable, and an empty result.

session.startjson
{
  "result": {
    "session": "s-bbc33c110a32d582774f552253d0695d",
    "scope": { "identity": "acme", "group": "notes", "project": "first" },
    "resuming": null, "others": [], "cursor": null
  },
  "written": [ { "object": { "table": "sessions", "id": "s-bbc3…" }, "version": 1 } ],
  "hints": [ { "hint": "no_catch_up" } ]
}

Retrieval

One read per family, fused by place rather than by score.

Free text runs over the prose a memory and a fact carry, vectors are stored in the records they describe, and a closed topic set runs over facts. A search with words and a vector is ranked by the engine by both at once with ORDER BY FUSE. What the store cannot answer it refuses and names.

Tenancy

One identity's whole world lives inside its own namespace.

The widest scope the model has is a single identity, so an authority spanning every tenant is not something that can be written down. Groups and projects sit inside it. A read is judged where it reaches, not merely where it stands: a caller granted at one project is refused a read of its neighbour rather than answered with the neighbour's records.

An authorization decision and the access it guards can never share a transaction, because a connection is fixed to one database when it opens. Revocation is prompt and it is not instantaneous: a call already in flight finishes, and the next call is refused.

The crates

Dependencies flow inward.

cli → core → store → types → constants, and each surface reaches ambient for the two things only a running binary can supply: the wall clock and the identifier source. Every crate names the split that justifies it.

The workspace
CrateHolds
tessari-am-constantsevery magic number, with its unit and its reasoning
tessari-am-typesthe record model: identifiers, scope, metadata, every entity
tessari-am-storerepository traits and their backends
tessari-am-coredomain services: the method set the surfaces render
tessari-am-authzthe authorization decision: one evaluator, with no reach into storage
tessari-am-ambientthe wall clock and the identifier source
tessari-am-clithe command line
tessari-am-restthe HTTP surface
tessari-am-mcpthe MCP surface