Memory

Memory gives the model a small key/value store that persists across runs, so it can keep durable notes and pick them up next time rather than rediscovering them. It is opt-in, agent-mode only, and never exposed over MCP.

Where it lives

internal/memory: the backend-agnostic Store interface and factory in store.go, the file backend in file.go, the on-disk format in frontmatter.go, and key validation in key.go. The four model-facing tools and the system-prompt index are in internal/util/builtin_memory.go.

Four tools over one interface

When memory is enabled the model gets four tools: memory_list returns keys and descriptions, memory_read fetches one entry, memory_write saves an entry, and memory_delete removes one. All four go through the Store interface, so the storage backend is pluggable behind them.

memory_listmemory_readmemory_writememory_deletememory.Storeone interfacefile backendone .md per keyunder memory/id
The tools depend only on the interface. The file backend is the one implementation today.

Keys, files, and races

A key is letters, digits, and . _ = -, with no leading or trailing dot and no .. (key.go:25). The slash that a NATS KV key also permits is deliberately excluded, so a key maps one-to-one to a flat filename with no separator to traverse. ValidateKey guards every operation and filters directory entries, which makes it a path-traversal defense as well as a format rule.

The file backend stores each entry as a markdown file with a YAML frontmatter description under memory/<identity>, where the identity defaults to the application binary’s base name. Two agents pointed at the same directory share a memory; the default keeps each separate. Create and overwrite use the filesystem for atomicity: a create links a staged temp file into place and fails if the name exists, giving a race-safe create guard, while an overwrite renames over the target. Content is capped at 64 KiB, sized to what a future NATS KV backend would accept.

The start-of-run index

At the start of a run, if the index is enabled, the stored keys and descriptions are injected into the system prompt inside a <memory-index> block, so the model knows what it has saved. memory_list is the live view during the run. The index is turned off with no_index.

Load-bearing decision

Memory is untrusted data, not instructions. The system note, the index framing, and the description sanitization all reinforce that a stored value is data the model saved, never an instruction to follow. A read opens with O_NOFOLLOW and rejects any non-regular file, so a planted symlink cannot redirect a read.

Next

Continue to Knowledge and RAG for the other opt-in, agent-only data store: a searchable document index.