Agents need to remember. That much is obvious. What isn't obvious — and what most agent frameworks get wrong — is that "memory" is several different things wearing the same name, each with its own shape, access pattern, and write rules. Treat them as one thing and the system rots; build them as separate primitives and the agent gets sharper with every conversation.
Glove's memory layer started as a single graph database for entities and grew into four orthogonal primitives. Each one earned its place by being structurally different from what already existed. This is the journey, and the philosophy that crystallised along the way.
The first design instinct is to give the conversational agent tools to add, link, and update memory as it talks. This is the wrong instinct. An agent in a conversation has narrow context, time pressure from the user waiting on a response, and an incentive to commit prematurely. It will create duplicate entities, miss merges, write half-formed records, and leave the graph in worse shape than it found it.
So Glove draws a hard line: the conversational agent only reads memory. A separate curator — itself a Glove instance, but one triggered by orchestration rather than by a user message — runs over conversation history asynchronously, extracts what's worth keeping, dedupes, links, merges. It can take its time. It can reason carefully. It can run multiple specialised subagents in sequence: classify, then link entities, then record events, then file artifacts.
This split is the spine of the whole system. Everything else falls out of it.
The first primitive is a typed graph. Node classes are registered up front (Person, Organization, Project); relationships connect them with their own typed properties (worksAt, contributesTo); identity is deterministic via configured key sets. When the curator says "add a Person named Don with email don@cradle.io," the adapter checks the email key set, finds the existing node, and folds the write in rather than creating a duplicate.
The trick that makes this hold up over time is multi-set identity keys. Real entities aren't uniquely identified by one field — a Person might be matchable by email or by (name + organizationId). Single-key identity is a toy; multi-set is the realistic case. Get this right at the contract level and the graph stays clean for years.
Entity memory captures stable facts. It doesn't capture events. "Don completed the Q3 presentation on April 15" isn't an entity — it's an episode. It happened once, at a moment, and is then a permanent fact about the timeline. Identity keys make no sense; semantic search over content does; time is a first-class field.
Episodic memory is its own adapter — append-only, time-indexed, keyed off natural-language content rather than typed identity. The participants reference entity node IDs, but the two adapters stay decoupled — the episodic adapter just stores strings and trusts the curator to keep them coherent. Episode kinds are registered alongside node classes (meeting, milestone, decision) so the curator picks from a known vocabulary.
Embedding for semantic search runs out of band — recordEpisode writes immediately and marks the embedding status as missing; a separate process picks up missing embeddings later and fills them in. This keeps writes fast and decouples embedding cost from the curator's hot path.
Then a third gap appeared. Research dossiers, whitepapers, transcripts, link collections, agent-generated notes — these aren't entities (they don't recur) and they aren't episodes (they aren't events). They're artifacts. Substantial content the agent should know exists and can read on demand, but shouldn't always pull into context.
The first sketch invented a bucket-and-topic structure. The reframe that cracked it: don't invent a new abstraction — give the agent a filesystem. A POSIX-style virtual filesystem with ls, read, grep, glob, edit. Code-trained models already know how to navigate filesystems; giving them one removes the need to teach a new mental model.
Files are text-only (markdown, plain text, URLs with optional cached extracts — binary deliberately excluded; if the data isn't textual, it doesn't belong here). Reads are line-bounded by default, fifty lines at a time, expandable on request. Edit follows the unique-substring-replace pattern Claude Code uses. Both the curator and the user can write — the user drops research notes via a UI, the curator enriches them with metadata and entity links later.
The fourth primitive is the one I almost didn't build, then realised I'd been hand-rolling it in every agent project for years. Context is the user's standing brief on themselves: identity, preferences, glossary, current task scope. The plumbing every agent needs and that nobody wants to write again from scratch.
Context is structurally different from the other three. It's not curator-extracted — it's user-configured. It's not lazily browsed — it's auto-injected into the system prompt at every turn so the agent always has it. It's not reader/curator-split — there's just one builder method, useContext(adapter), and the conversational agent gets both read and write tools because users naturally tell agents "remember that I prefer X."
External updates are out of scope for the package — the adapter exposes set / update / unset and however your settings UI or API talks to it is up to you. The package's job is just to provide the contract and to handle the system-prompt composition cleanly: developer prompt first (character, guardrails), user context after (preferences, glossary), regenerated every turn so external updates are reflected immediately.
Across all four primitives, the same patterns held:
Adapters all the way down. Same shape Glove already uses for storage, models, display. BYO backend; the contract is what matters. Storage backends ship as separate packages so consumers don't pull in dependencies they don't need.
Composition over configuration. When the question came up about whether large schemas would balloon tool-description token costs, the answer turned out to be architectural rather than configurational. You don't add scope-restricting API knobs; you split the curator into specialist subagents, each attaching only the adapters it needs. Each subagent's tool descriptions render only the slice of schema relevant to its role. The system scales by adding agents, not by adding flags.
Provenance on every write. Every node, edge, episode, file, and context entry carries an append-only log of who wrote what when, with what intent. This is what makes the system debuggable — without it you have a database; with it you have a memory you can reason about.
Primitives, not policies. The package provides strong primitives (identity-keyed upsert, link target rewrites, participant rewrites, async embedding lifecycle) and stays out of orchestration policy. When to run the curator, how to retry, what to do on conflict — that's all Station's territory or the consumer's. glove-memory just gives you something solid to build that on.
Reconciliation is explicit. The package doesn't cascade across adapters. When you merge two entities, episodes that referenced the old ID don't update on their own — but replaceParticipantId is right there as the primitive the orchestrator reaches for. Cleaner than implicit cascades because you always know what's happening.
Four primitives, one package, one adapter pattern. Plug in whichever subset you need. The conversational agent gets readers; a Station-orchestrated curator gets writers; users plug into resources and context directly. Memory becomes something you compose rather than something you configure.
Less plumbing. More shape.
See Memory for the full API reference.