Documents it can search
A memory is a named, searchable corpus. It is not the conversation and it is not a database — it is a body of documents someone put there on purpose, that an agent can search by name.
memory_search("handbook", "what is the travel policy")Two kinds, and the difference is only where the documents live.
| kind | the documents are | good for |
|---|---|---|
| local | on this machine, ingested into an index | your own files |
| served | on another agent, reached over DDE | a corpus too big, too private, or too shared to copy |
Where these commands go
Section titled “Where these commands go”Two different things, and mixing them up is the usual confusion:
| the workspace | where you add and manage memories. The Documents pane has Add memory: point it at a folder, give it a name and a description, and it ingests |
memory_search(...) | a tool the agent calls while answering. You never type it |
hexaeight-engine --memory-... | the command line, for bulk work only: very large ingests, rebuilding an index, checking a store |
hexaeight-engine ships with the agent, under ~/.heia/runtime/harness/. Its --root is the
folder holding memories/. You only need it for the bulk cases at the end of this page —
everything ordinary happens in the workspace.
A local memory
Section titled “A local memory”In the workspace, open Documents and choose Add memory. Point it at a folder and it ingests
every .md, .txt, .pdf and .html underneath.
Give it a name (handbook) and a description — the description is the part that matters.
The description is load-bearing. It is the one line the model sees when deciding whether a question belongs to this corpus at all. “Company handbook” is nearly useless; “policies, benefits, travel, expenses, leave — what an employee is entitled to and how to claim it” tells the model when to reach for it.
A served memory
Section titled “A served memory”The corpus stays where it is. The calling agent holds only a pointer — a small file at
<harness-root>/memories/<name>/remote.json.
You do not usually write it by hand. The workspace writes it when you add a served memory, and
hexaeight-activate add-api prints the exact fields to paste in. It is shown here so you can read
one and know what it means:
{ "name": "erag", "remote": "erag", "agent": "corpus.example.com", "api": "erag", "path": "/heia/search", "capability": "erag", "description": "A software company's internal record: Slack, email, tickets, PR discussions, design docs, incidents and contracts. Search it for what was decided, shipped, measured or agreed. Each document has an id like dsid_<hex> — cite it. If a search misses, try the words the AUTHORS would use, not a reworded question.", "docs": 511952}The agent that serves it is an API agent. The caller reaches it by name over an encrypted channel — it never learns the host or the port.
Two shapes of pointer, and they behave differently
Section titled “Two shapes of pointer, and they behave differently”| the pointer names | how it is reached |
|---|---|
agent + api + capability | a service_call over DDE — encrypted, policy-gated, by name |
host + port + token | a direct HTTP call — no identity, no policy |
Prefer the first. The second exists for a service on the same machine and gives up everything the platform is for.
Write the description for the model, not for you
Section titled “Write the description for the model, not for you”This is the single highest-leverage thing in the file, and it is read live — improve it and the next question uses the better one, no restart.
Three things belong in it:
- what is in here, in the words the documents use
- what to cite — if documents have ids, say so and say to quote them
- the vocabulary warning, if the corpus has house terms
That last one is not theoretical. A search for a “time limit” metric failed repeatedly against a corpus whose engineers had called the same thing a timebox. The documents were right there. No amount of rephrasing the question found them, because the question and the corpus did not share a word.
Big corpora
Section titled “Big corpora”Past a few hundred thousand documents, ingest in shards and then either group them or merge them.
# ingest as N pinned shardshexaeight-engine --memory-add mycorpus --shard 0/8 --defer-index# … one process per shard …
# then EITHER: group them — no copy, no extra diskhexaeight-engine --memory-group mycorpus --members 'mycorpus-sh*' --root <root>hexaeight-engine --memory-group-router mycorpus --root <root>Prefer the group. Measured on 8 shards and 24 million chunks: the group router is 5 MB and about ten minutes. A full merge of the same corpus needs twice the shard total on disk — and on a 61 GB machine it was killed by the kernel twice while building the index, after the concatenation had already succeeded.
manifest.jsonappearing does not mean a merge finished. It is written when concatenation ends, before the index build — the long part. A merged store with noterms.idx,centroids.binorivf-vectors.binis unfinished whatever the manifest says.
Checking a memory is live
Section titled “Checking a memory is live”hexaeight-engine --memory-list <name> --root <root>hexaeight-engine --memory-search <name> --root <root> -p "a real question"If a search returns nothing, check in this order: is the name right, is the pointer’s agent
reachable, and does the corpus use different words than the question.