Decisions
Why Link Memory is named, writes, indexes, is sandboxed and searches as it does.
Link Memory
What Link Memory is called, what it writes, and whose conversations it remembers.
What is Link Memory called?
Link Memory, the plain word, no brand. You type lnk agent memory start link; its program is lnk-link-memory and its plugin link-memory,
mapped the way Link Harness's is (MEMORIES in the harness plugin).
How does your agent reach its memory?
As a tool outside its sandbox, through the bridge every tool uses (lnk sandbox tool add), at $LNK_MEMORY: one way in for every harness, the
calls logged and gated by the proxy. The tool is the agent's own,
memory-<agent id>, defined again at a start when its settings, the
engine or Link changed since, or the tool is gone, so it follows the
agent to another machine and a new release of the engine. The harness
gets one variable, whatever the agent's name.
Does Link Memory write?
One file only: the agent's notes, memory/notes.md, through remember.
Its sandbox writes the folder Agent/memory/, not the file alone, since
a file is replaced whole only by a rename, which takes its folder.
Everything else it searches, reads and lists, and never changes.
Why traverse a parent without reading it?
The agent's private parent folder is opened for traversal without
reading its entries. Notes and chat copies are opened through their
own granted child folders, so saving notes needs no read access to the
rest of Agent/.
Its notes
The notes are what an agent keeps in mind in every conversation, so
they're in its prompt, and a tool writes them rather than the harness,
so any harness with Link Memory takes notes the same way. They're one of
its instructions, so the sandbox file decides as it does for the rest:
where [files] keeps instructions/ read only, Link names no notes
file to the engine, which then offers no remember.
Never past its size
remember doesn't ask you first, as the agent's own edits to its
instructions don't, and it never writes past the spec's [tool.memory] notes, 4 KB by Link's, so the notes stay a small part of every prompt.
There are two keys for the notes: [tool.memory] notes, what remember
writes up to, and [instructions.max] notes, what the prompt holds,
Link's 4 KB each. That is about 1,000 tokens in every prompt, and a file
edited by hand past the first is still cut by the second.
Whose conversations can have the agent remember?
The owner's alone, where the harness is sent others' messages: a
teammate's, a team's, a stranger's and a subagent's conversations get
every tool but remember, so nobody else has the agent note something
for every conversation after. A chat the owner shared (lnk agent share) counts as the owner's: its members can make the agent do all it
can, its memory included, and an owner who wants less shared makes a
second agent. A call that names no conversation is refused, as one can't
tell whose it is.
How are an agent's notes kept?
As a markdown file, a line a note, which you read and edit as any other.
remember adds a line, or changes or forgets the one line holding a
piece of text it's given, so the model never rewrites the whole file and
loses a note by accident. It writes the file whole in one step, through
its folder's handle and never through a link, one writer at a time.
What does Link Memory add to a folder?
Only what's true of any folder of text: search by words and meaning, filters, what changed since, links, a size limit. It assumes no kind of note (people, projects, facts), runs no model over the notes, and imports nothing. An engine built around one way of working plugs in by the engine contract instead.
What does a memory engine's contract fix?
Only how the engine starts: install, and command <folder> <state>
printing the command that serves MCP over stdio and which calls don't
ask you first (link_memory_contract), with the agent's notes file in
its environment where it may write it. The bridge passes each server's
tools through, so no engine's names are translated, and a harness reads
each tool's description. Engines compete on what they serve, not on a
shape Link picked.
What memory indexes
Which folder memory reads, and how its index is kept.
Which folder does memory read?
The agent's own: its Home, and its conversations in its own folder. One folder shared by several agents would be a new decision about the layout, and agents are kept apart everywhere else.
Why does memory index only memory/ and the conversations?
So what's searchable is what you put there, the same on every machine,
and a move never changes it. Indexing the whole files folder found
drafts, scratch files and a repository's code among your documents, and
paid to embed them. memory/ is a folder of the layout for it;
everything else is still read by file, and a skill by its path through
memory's read.
Why does memory read PDFs and Word documents?
Because the documents people keep are often PDFs: a tax report, a lease.
Memory extracts their text for its index, on every machine; the file
stays as it is, and file still reads text only. A document over 32
MiB, or text past 2 MiB, is left out rather than half read. Their
parsers run in a child process, memory's own program again, given no
environment, no key and limits: the process serving memory holds every
bound agent's key, and a parser is where a crafted file would get in.
Where are conversations in memory's folder?
In chats/, where Link Harness keeps them, a folder per
conversation, its conversation.md the one indexed, never the event
files. A conversation kept compact or by a store driver has none on
disk: memory makes the same copy from its events, at the same path.
Memory follows the harness, and an end-to-end test holds the two
together. A search says which results are conversations, so a document
isn't lost among the chats about it.
Where is memory's index kept?
The index lives in the agent's memory collection at
Agent/memory/<engine>, outside the harness's reach. It follows the
agent's folder and is included when lnk uninstall removes agents.
How is an index kept in a bucket?
The index is split into 8 MiB segments named by their SHA-256, with a
manifest written last (link_store_contract::files::index). A write
succeeds only against the version it read. Changed segments are
uploaded, and a concurrent writer receives a refusal and reads again,
preserving both writers' changes.
Memory's sandbox
Why one process serves every agent's memory, and what its sandbox reaches.
Why does one process serve every agent's memory?
A session of memory on its own is a sandbox, the engine and its model server: about 37 MB and six processes, started for each agent, and again after it's been idle. Many agents on one machine would pay that many times over, for one program reading folders.
One engine for an owner
So an engine that can serve many folders (Link Memory) runs once for an owner's agents, started by the first session that needs it and ending a few seconds after its last, and each session is a small process that passes its messages on. Each session is answered from its own agent's folder, named by Link outside every sandbox, never by the agent.
Told which agent
A team's shared tool runs one server for every member's session, as is, which an agent's memory can't: each session reads a different agent's folder, so the engine itself is told which agent each session is. One owner's agents share it, never two owners': the folders its sandbox holds together are all one person's, and no agent reaches the process but through the session Link opened for it.
Why does the memory engine run in a sandbox too?
It runs outside the agent's sandbox, as every tool does, but it needs
nothing a tool usually runs outside for: no logins, no desktop. So it
gets the least: it reads Home, the agent's conversations and skills in
its own folder, and its program, and writes its state folder and, for
the notes, Agent/memory/. Link Memory already reads and writes nothing
else; the sandbox makes that true of any engine. It writes the folder
its notes are in, not the file alone: a file is replaced whole by
renaming a new one over it, which takes its folder.
Why is memory's model served outside its sandbox?
Link Memory searches by meaning with a model lnk model serve serves,
and running that from inside would need lnk, the models plugin and
what they run, so its sandbox read the whole folder its program is in.
Started outside
Instead Link starts the model server for it outside, once for the service its owner's agents share, and gives it the address, as a harness is given its tools'. The address is a port chosen before the server starts, so a runtime that comes up late is found there, its server started again until it does, without the engine started again. Its sandbox reads its own program and nothing beside it.
Why does Link Memory's sandbox have the network?
To reach its embedding model on this machine: on Linux, without the network a sandbox reaches none of this machine's ports. The other way, the proxy's filtered path to a model, would give the engine a proxy of its own for one port. It still reads only its folder, and writes only its state and its notes.
Search
How memory searches by meaning, ranks, merges and keeps its vectors, and how much a call gives.
How does memory search by meaning?
With an embedding model on your machine, served by lnk model serve, so
memory stays keyless and free. A hosted model through the proxy would be
one more source, but memory is kept keyless. Each document is split at
its headings, then at blank lines, into chunks of up to about 1,500
characters, each embedded with its document's title in front.
How does memory rank what it finds?
By its words (SQLite's bm25, the title counting four times the body) and by its meaning, the two lists merged by their ranks. Within each list, documents within a tenth of the best score around them match about as well, and the newest of them comes first: a newer note beats an older one saying nearly the same, never one that matches clearly better. A title from a file's name is embedded as its own chunk, so it counts by meaning as it does by words.
Copies
A copy (all the same words, or, from twenty words, nine in ten of them)
comes once, the others named in its copies, the shorter path kept. A
test of sixteen questions over a fixed folder (tests/quality.rs) holds
how many find their document first, so a change can't make search worse
unnoticed.
How do words and meaning merge?
Reciprocal rank fusion: each ranks its best 50 documents, and a document
scores the sum of 1 / (60 + its rank) in each. There are no scores to
calibrate between the two, and a new model needs no retuning. There is
one search, no mode to pick: matched says why each hit came back.
Where are the vectors kept and compared?
In the same SQLite index, a blob of numbers per chunk with the model's name, compared in Rust: 100,000 chunks of 1,024 numbers is well under a second, with no new dependency. Comparing is one function, so another store can replace it.
Kept between searches
A server keeps the vectors in memory between searches. The index counts every change to its chunks, by triggers in the file, so a change by the embedding thread or another server over the same file counts too, and the vectors are read again whenever the count moved: a changed or deleted chunk's old vector is never used.
Why does embedding run in the background?
So the first index doesn't hold up a search: what's embedded is searched by meaning, the rest by words, and the reply says how far it got. It needs the index in a file, which the embedding thread opens too, and which keeps each vector from one session to the next, so only what changed is embedded again.
Which embedding model does memory ask for?
qwen3-embedding, Apache-2.0 and many languages, over the smaller
nomic-embed-text. A model under terms that aren't permissive isn't
asked for.
Another model
The agent's spec can name another, or none to search by words only. A
spec that names something that isn't a model's name is refused, so a
typo never runs another model than asked.
How does an agent catch up on what changed?
list {since}, with since on search too: what was changed or first
seen after a time, each new or changed, and what was removed. The
index notes when it first saw each document, so a file copied in with an
old date is new all the same, and keeps the paths and titles of what was
deleted, the latest 10,000.
What was there before
What was in the folder when memory first read it counts as there before,
not new, so turning memory on doesn't make everything news. since
takes a date, since a model writes one more reliably than a count of
seconds, or the seconds list gives. It holds for any folder of text,
as everything Link Memory adds does.
How much does a memory call give?
At most about 6,000 tokens, four characters each, unless the call asks
for another size: under the 32 KiB Link Harness keeps of a tool's
answer, so an answer arrives whole rather than cut mid-way. search
gives whole results and read whole lines, at least one, and each says
where it stopped (next), so the next call carries on from there rather
than starting again.
What's cut
Only a single line longer than the size is cut, and the read says so
(cut). list and links keep the same size, leaving out whole
entries that don't fit, and a title is at most 200 characters, so no one
document fills an answer.
How does memory follow links?
links {path} gives what a document links to and what links to it, from
markdown links and wiki links, the two ways notes link in a folder of
text. The index keeps each link as written, resolved against the folder,
and matches it to documents when asked, so a link to a note made later
starts working without reindexing.
Wiki links
A wiki link names a document by its path or its file's name; several of that name, the shortest path, as notes apps do. Nothing is followed on disk: a link only names an indexed document, and one to the web or out of the folder is no link. It is a fourth read-only call, so it never asks you first. A document keeps its first 1,000 links, and none longer than 512 bytes.