Skip to content

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.

kindthe documents aregood for
localon this machine, ingested into an indexyour own files
servedon another agent, reached over DDEa corpus too big, too private, or too shared to copy

Two different things, and mixing them up is the usual confusion:

the workspacewhere 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.

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.

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 nameshow it is reached
agent + api + capabilitya service_call over DDE — encrypted, policy-gated, by name
host + port + tokena 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.

Past a few hundred thousand documents, ingest in shards and then either group them or merge them.

Terminal window
# ingest as N pinned shards
hexaeight-engine --memory-add mycorpus --shard 0/8 --defer-index
# … one process per shard …
# then EITHER: group them — no copy, no extra disk
hexaeight-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.json appearing does not mean a merge finished. It is written when concatenation ends, before the index build — the long part. A merged store with no terms.idx, centroids.bin or ivf-vectors.bin is unfinished whatever the manifest says.

Terminal window
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.