← Writing

Memory is five things, not one

Vectorizing everything is not a memory system. Glove's memory is an entity graph, a timeline, a filesystem, ambient context, and forms, each answering a different question.

A spacecraft cabin wall used as a memory system: pinned photographs connected by string, a timeline of dated cards, a filing cabinet, sticky notes, and a clipboard.

Ask most agent frameworks what memory is and you get the same answer: chunk the text, embed it, store the vectors, retrieve the nearest ones at query time. Call it long-term memory. Ship it.

We think that answer confuses a retrieval technique with a memory system. Retrieval-augmented generation is a fine way to find a passage that resembles a question. It is a terrible way to know who your customer's manager is, what was decided last Tuesday, where the contract lives, or that the user wants everything shipped to the office. Those are four different questions with four different shapes, and forcing them through one similarity search gives you an agent that is confidently vague about all of them.

Glove's memory package is five subsystems. Here is why it is five, what each one is for, and the design rule that ties them together.

The five

Entity memory is a typed property graph. People, organizations, projects, and the relationships between them. It is schema-first: you declare node classes with validated properties and, crucially, identity keys. A person is identified by email; an organization by domain. That makes every write a deterministic upsert. Searching for a person by name and finding them twice is the single most common memory bug in agent systems, and the identity key removes it structurally. Queries traverse the graph with bounded fan-out. This is the subsystem for "who."

Episodic memory is an append-only timeline of things that happened. Meetings, conversations, decisions. Each episode has a registered kind, participants that point at entities, a time it occurred, and searchable content. Time is a first-class field, not metadata. You can ask for everything with this participant in this window without a single vector. This is the subsystem for "when, and what happened."

Resources is a POSIX-style virtual filesystem. ls, read, grep, glob, edit. Notes, transcripts, documents. Files can link to entities and episodes through metadata, which gives you a third retrieval dimension. Roots are declared in the schema, so the agent navigates a tree you defined rather than a path it invented. This is the subsystem for "where is the thing."

Context is the small set of standing facts the user told the agent to remember, injected into the system prompt every turn. "Always ship to the office." "I prefer terse replies." No extraction, no retrieval. It is deliberately the exception to every other rule in the package: one registration, read and write, on the main agent, because it is the user's own words and the agent should always have them.

Forms are structured collection over a conversation. Sixty fields gathered by talking, not by a wizard. A form is defined in code, Zod schema plus steps and gates in one builder, and the agent sees only a projection of evaluated state: the current step, pending fields, what is coming. Writes are never gated. A user who answers question six while being asked question two has answered question six. Each field is an append-only revision log with a cursor, so undo and redo are pure cursor moves. The wizard, deleted.

Why not one

Because the questions are different, and so are the correct answers.

"Who did we meet with from Acme?" is a graph traversal. It has an exact answer and should return it deterministically. "What did we discuss about pricing?" is a ranked search over content, blended with recency. "Where are my notes on the contract?" is a path filter. A vector store handles the middle one and fakes the other two. When the fake works it looks like magic. When it fails it looks like the agent is lying, and you cannot tell which from the outside.

Splitting the subsystems also means embeddings become opt-in instead of the mechanism. Finding episodes by kind, participant, or time window needs no vectors at all. Only free-text search over content needs a ranking backend, and even there the package ships a fuzzy lexical search with zero external services. The embedding lifecycle is exposed as a generic background-indexing seam, so you can plug in FTS5, Postgres tsvector, BM25, or a proper vector index when you have one. Most teams need it later than they think.

Provenance, not scores

Every write to entity or episodic memory carries a source, an actor, a timestamp, and optionally a rationale, and it is appended, never replaced. A similarity score tells you how close a chunk is to a query. Provenance tells you why the agent believes something. "Why does the agent believe this" stays answerable a year later. For anything an agent will act on, that is not a nice-to-have.

The rule that holds it together

Here is the recommendation from the docs that surprises people: do not attach the memory tools directly to your main agent.

Instead, build small subagents. A lookup agent that sees only the entity classes. A recall agent that sees only episode kinds. A find-notes agent that sees only resource roots. The main agent routes to whichever one answers the question at hand.

Three reasons, all practical.

The prompt surface stays bounded. The main agent's tool descriptions do not have to render every node class, every relationship type, every episode kind, and every resource root on every turn. Token cost scales with the role, not with the size of your ontology.

Routing gets sharper. "Which memory answers this?" is an easier decision than "which of these eight tools?", and the model makes it better.

And readers structurally cannot write. A retrieval subagent attached with the reader hook has no write tool. The affordance is not there. It cannot mutate memory, not because a prompt told it not to, but because there is nothing to call. Curation, the extraction and writing, runs as a separate orchestrator-driven process with its own narrow surface.

The adapters are shared underneath, so splitting the tools costs nothing at the storage layer. You are dividing the interface, not the data.

Bring your own storage

Every subsystem stores through an adapter you can replace. The package ships in-memory reference implementations so you can start in a test. Production backends are yours: your Postgres, your SQLite, your object store. Two exposure axes are independent: allowlists remove an affordance, so a tool never reaches the model, and path policies remove a capability, so the adapter refuses however the request arrives. Layering merges a shared read-only stratum with a private writable one into a single view, team handbook underneath, this user's notes on top.

That is the through-line of everything we build. The framework owns the shape of memory. You own where it lives.

What memory is for

The point of memory in an autonomous system is not to make the agent sound familiar. It is to make the agent right about the things it will act on, and auditable when it is not. Five narrow, typed, provenance-carrying subsystems get you there. One big similarity search gets you a demo.

Cradle ResearchBuilding Primitives for Autonomous systems.