Linking memories: a small graph that keeps decisions connected

Memory links are directed edges with a kind and optional weight. They are idempotent to write, visible only when both ends are, and capped at 1,000 per memory.

Illustration: A small friendly robot with a round camera-eye head ties short lengths of string between blank index cards pinned to a cork board, like a detective's board, with one card at the center and a few cards around it.

A memory link is a durable, directed edge from a memory you own to any memory you can see. Each link has a kind, related by default, and an optional weight from 0 to 1. Writing the same link twice changes nothing. A memory can hold up to 1,000 outgoing links, and the dashboard draws the graph.

A directed edge with a kind and a weight
What writes an edge
memory__remember
related_ids at save time
memory__link_memories
any kind, optional weight 0 to 1
memory__archive_memory
writes supersedes only
A memory you own
up to 1,000 outgoing links
Where it can point
Your own memory
a decision and its constraint
A teammate's shared memory
any memory you can see
A teammate's private memory
invisible to you, so no edge
A link runs from a memory you own to any memory you can see.

Memories are saved one at a time: a preference, a decision, a constraint, a named relationship. The useful ones depend on each other. A release-day decision rests on a customer constraint. A preference belongs to a person. A runbook applies to one service. A link records that dependency as data instead of leaving it in the prose of each memory.

A link is named by its two ids and a kind. It runs from a memory you own to any memory you can see, so you can point your own memory at a teammate's shared one, and you cannot attach edges to a memory that is not yours. The related_ids argument of memory__remember, memory__ingest and memory__update_memory writes related links at save time. memory__link_memories writes any kind, such as depends-on, with an optional weight.

FieldValuesNotes
directionfrom a memory you own, to a memory you can seeone edge, one direction
kindrelated by default, or any name you choosesupersedes is reserved
weight0 to 1, optionala new weight replaces the old one
outgoing links per memoryup to 1,000link_capacity_exceeded past the bound
kinds toward one other memoryup to 16the same bound applies

One kind is reserved. supersedes is written by memory__archive_memory when a memory is retired in favor of another, and only by it. The memory page documents every field.

Writing a link is idempotent, and that is deliberate. Agents retry. A client times out, a session restarts, the same instruction runs twice. If a link call created a new edge each time, the graph would fill with duplicates that mean nothing and cost capacity.

So the same call again changes nothing. A call with a new weight replaces the old weight on the same edge. memory__unlink_memories removes exactly the link its key names, and no other. An agent can link at the end of every session without checking first whether it already did.

A link is visible only when both of its memories are. memory__list_memory_links reads a memory's links back, newest first, outbound or inbound, and lists only links whose two memories you can see. A link to a teammate's private memory stays invisible to you, as that memory does.

This is the same boundary memory itself has, applied to the edges. Identity comes from the credential on the request, every memory carries a scope, and the database enforces it. A link cannot leak the existence of a private memory, because the link is filtered by the same rule as the row.

What are the limits?

A memory can hold up to 1,000 outgoing links and up to 16 kinds toward any one other memory. Past either bound the call answers an isError result:

{ "error": { "code": "link_capacity_exceeded" } }

Treat it like the other tool-level codes in the errors reference: branch on structuredContent.error.code, and do not retry, because the bound does not move. Unlink something, or link from a different memory.

The bound is generous for the intended use. A memory with a thousand outgoing edges is a hub, and a hub usually means something is being used as an index that should be a search instead.

Link when a memory is only correct in the light of another one. A decision and the constraint behind it. A preference and the person it belongs to. An operating rule and the service it covers. These are the categories the docs say belong in memory in the first place, and the link is what lets an agent that found one of them find the reason for it.

Do not link to build an archive. Memory is for context that improves a later action, and the graph serves that. Transcripts, application data and secrets do not belong in memory, and linking them does not change that.

Two patterns work well:

  • At save time, pass related_ids so a new decision points at the constraint or preference it depends on.
  • When a memory is retired, let archive write the supersedes link, so an agent holding the old id follows the pointer forward.

How does the dashboard show it?

Dashboard → Memory draws every link you can see. The graph view is where a person reads what the agents have been connecting: which decisions cluster around one constraint, which memory has become a hub, which old memory still has a supersedes pointer to follow. The same page opens a memory's detail view, where you can inspect and delete content.

Memory operations, links included, cost 0 credits per call. The graph is part of the org-owned memory described in the Introducing CoreSpeed post: it belongs to the organization, and every agent you sign in works from the same one.

FAQ

Can I link to a teammate's memory? Yes, if you can see it, which means a shared one. The link runs from a memory you own. You cannot attach a link to a memory you do not own.

What happens if my agent links the same two memories twice? Nothing. The same call again is a no-op, and a call with a new weight only updates the weight.

Can I write a supersedes link myself? No. supersedes is reserved for memory__archive_memory, which writes it when a memory is retired with a named successor.

What does link_capacity_exceeded mean? The memory already has 1,000 outgoing links, or 16 kinds toward the same target. Remove a link or link from another memory; retrying does not help.

Do links show in search results? Search returns memories. Read a memory's links with memory__list_memory_links, or look at the graph in Dashboard → Memory.