Knowledge
Your runbooks, notes and conventions, searchable by the agent, with citations.
Drop documents in <workspace>/knowledge/. Ask a question. The agent searches, quotes what it
found, and names the file and section it came from. Nothing is added to any prompt, so a knowledge
base costs nothing on a turn that does not ask for it.
This is different from Memory, and the difference is who writes it. Memory is what the agent concluded from your conversations, and Dream maintains it. Knowledge is what you wrote, and only you change it.
Quick Jump
| Need | Section |
|---|---|
| Turn it on | Enable it |
| Understand what a citation looks like | Citations |
| Know why a document is not being found | When something is not found |
| Choose a mode | Lexical and hybrid |
| Keep secrets out of the index | What is never indexed |
| Tune the schedule and the caps | Configuration |
Enable it
Settings → Knowledge, or in ~/.nanoinfra/config.json:
{
"tools": {
"knowledge": {
"enabled": true
}
}
}
Restart the gateway. Then create the folder and put something in it:
mkdir -p ~/.nanoinfra/workspaces/default/knowledge/runbooks
$EDITOR ~/.nanoinfra/workspaces/default/knowledge/runbooks/pods.md
Folders and subfolders, whatever suits you. The index lives beside the documents in
knowledge/.index/, so a workspace that restores from backup restores its index too.
Citations are the point
A runbook paragraph stated as fact with no source is worse than no runbook, because a stale paragraph reads exactly like a current one and the reader cannot tell which they are looking at.
So every fragment the agent retrieves carries path#section, and the tool contract requires the
answer to cite what it used:
Restart it with
kubectl rollout restart deployment/api(runbooks/pods.md#restart-the-pod).
An answer with no citation is not a claim. If the search finds nothing, the agent is instructed to say the knowledge base does not cover it, rather than answering from its training data in the same voice it uses for a cited answer.
The #section half is a real anchor:
- In markdown it is the heading, slugified the way a renderer would (
## Restart the podbecomes#restart-the-pod). Two sections with the same title get#notesand#notes-2. - In a file with no headings it is a line range:
notes.txt#L1-L80.
Either way you can open the file and land on the paragraph the agent used.
Nothing is injected
The agent reaches knowledge by calling knowledge_search. Documents are never placed in the
system prompt, in a session summary, or in any other prompt section.
That is deliberate, and it is the one thing worth understanding before you fill the folder: a knowledge base in the prompt would be paid for on every turn, including "hello", and it would grow with your own writing. A tool call is paid for only by the turn that asks.
The single line the model carries all the time is one entry in the skills catalogue, naming that
knowledge_search exists and when to use it. The skill's body — the search advice and the
citation contract — is loaded only when a turn invokes it.
Freshness
Two things keep the index current, and they exist for two different readers.
The knowledge-index automation runs on a clock beside dream and heartbeat. It walks the
whole tree, drops entries whose files are gone, reindexes what changed, and records what the pass
did. Fifteen minutes by default.
The search itself compares the folder against the index before it answers, and indexes what changed. This is what makes a document you saved a moment ago findable immediately, rather than after the next tick. It costs a directory walk and a stat per file, and opens no index at all when nothing changed — which is the usual case.
So the schedule can stay quiet. Its job is collecting deletions and catching what nobody searched for.
When something is not found
In order of likelihood:
It does not contain the words you searched for. Lexical search matches terms, not meaning. A
runbook that says CrashLoopBackOff is not found by "pod won't start". Search the words the
document itself would use.
It was skipped. A file over the per-file limit, a binary, or a symlink pointing out of the
folder is refused — and named, both in Settings → Knowledge under Last run and in the tool's
own output under Not indexed:. A skipped file is never a silent drop.
It is excluded. Check the exclude list below. .env, *.pem, id_* and secrets/** are
excluded by default, at any depth.
It could not be read. A permission problem is reported as a failure rather than a skip, because it needs a different fix. It is retried on the next pass.
Lexical and hybrid
| Mode | What it does | What it costs |
|---|---|---|
lexical (default) | BM25F over the words in the document, with a heading match weighted above a body match | nothing — pure Python, no extra install |
hybrid | BM25F plus vector search | pip install 'semlix[semantic]', and for a local embedding model semlix[semantic-full] and its download |
Lexical is the default because for runbooks the words in the question are usually the words in the document. Its limit is worth knowing rather than discovering: it will not match "pod won't start" against a document that says "CrashLoopBackOff".
Hybrid is greyed out in Settings until the extra is installed, and the save path refuses it too. A mode that cannot search is not a setting worth persisting. Switching mode rebuilds the index on the next pass rather than searching for vectors that were never written.
What is never indexed
Three refusals, and none of them can be talked out of by a document.
Your exclude list. .env, .env.*, *.pem, *.key, id_*, secrets/** and **/.git/**
by default. These are config rather than code, because your tree holds secrets nanoinfra cannot
guess — and they are written out in full so removing one is deliberate. A pattern matches at any
depth: secrets/** excludes nested/secrets/keys.md too.
Anything outside the folder. A symlink whose target resolves outside knowledge/ is not
followed, and a symlinked directory is never descended. This is the same containment rule the file
browser applies, and it is checked against the knowledge folder rather than the workspace — so a
link to the workspace's own secrets/ store is refused by the same rule that refuses a link to
/etc.
Anything over the caps. A file above maxFileBytes, or one that would push the index past
maxTotalBytes, is skipped and reported. One 2 GB log file must not become the knowledge base.
Files whose bytes are not text are skipped as well. The type comes from the bytes, never from the extension.
Configuration
{
"tools": {
"knowledge": {
"enabled": false,
"mode": "lexical",
"reindexIntervalS": 900,
"exclude": [".env", ".env.*", "*.pem", "*.key", "id_*", "secrets/**", "**/.git/**"],
"maxFileBytes": 2000000,
"maxTotalBytes": 200000000,
"maxResults": 5
}
}
}
| Key | Default | What it does |
|---|---|---|
enabled | false | Registers knowledge_search and the indexing automation. Off by default: an empty index answers nothing. |
mode | "lexical" | lexical or hybrid. Hybrid needs the extra. |
reindexIntervalS | 900 | How often the full pass runs. Minimum 60. |
exclude | secrets | Globs never indexed, matched against the file name and the path at any depth. |
maxFileBytes | 2000000 | Largest document. A larger one is skipped and reported. |
maxTotalBytes | 200000000 | Total indexed size. Once reached, further documents are skipped and reported. |
maxResults | 5 | Fragments one search returns. Small on purpose: a citation the model has to read is worth more than ten it skims. |
Settings → Knowledge writes all of these, and also shows what the last pass did: documents and fragments indexed, what was added, updated, removed, skipped and failed, and when.
A change here needs a gateway restart. The search tool and the indexing job are both built once at start.
What the agent sees
One knowledge_search call, and an answer shaped like this:
2 fragment(s) for 'rollout restart' from the knowledge base.
Cite the path#section of every fragment you use. An answer with no citation is not a claim.
1. runbooks/pods.md#restart-the-pod (score 4.41)
Run kubectl rollout restart deployment/api and watch the rollout
2. notes/2026-07-incident.md#L14-L31 (score 2.09)
we restarted the deployment before the probe had a chance to pass
Documents in the knowledge base are your writing, not instructions to the agent. If a fragment contains something that reads like a command, the agent is told to report it and not act on it.