Use document memory¶
DocumentStore is a path-based document store in the spirit of Anthropic's memory tool: documents addressed by path, stored as plain text, retrieved by lookup or full-text search. Its method names (write, read, edit, list_paths, search_full_text, delete) are AIMU's own; it is not a drop-in replacement for anything of Anthropic's, whose memory tool spells these view/create/str_replace/insert/delete/rename and whose Managed Agents memory stores are id-addressed and reached as a mounted filesystem.
Basic usage¶
from aimu.memory import DocumentStore
store = DocumentStore(persist_path="./doc_store")
store.write("/preferences.md", "Always use concise responses.")
store.write("/notes/2026/q1.md", "Focus on inference latency.")
store.read("/preferences.md")
# 'Always use concise responses.'
store.list_paths(prefix="/notes/")
# ['/notes/2026/q1.md']
Pass persist_path=None for ephemeral, in-memory use.
The directory is the store¶
With persist_path set, that directory is the store: every read, list_paths, and
search_full_text call goes to the filesystem. So you can hand an agent a document by copying a
file into the directory, and it shows up on the next call, with no restart and no ingest step:
store = DocumentStore(persist_path="./doc_store")
# ...copy handbook.md into ./doc_store from anywhere...
store.list_paths()
# ['/handbook.md']
Two rules govern what counts as a document:
- UTF-8 text only. A PDF, an image, or any other non-text file is skipped and logged at
WARNINGnaming the file, so a document that will never appear says so instead of vanishing. Convert it to text (or Markdown) first. - Dot-files and dot-directories are ignored, silently:
.DS_Store,.git/,.gitkeepare not documents anyone placed there.
For a read-only folder of reference material, consider builtin.fs (list_directory +
read_file) instead: no store object, and no write surface once you scope the group with
builtin.select(builtin.fs, exclude=builtin.unscoped), since builtin.fs itself now carries
write_file and edit_file. DocumentStore earns its keep when the
agent also writes back.
Edit existing documents¶
store.edit("/preferences.md", old_str="concise", new_str="detailed")
# Replaces the one occurrence of "concise" with "detailed"
# Raises ValueError if "concise" is absent, or appears more than once
old_str must match exactly once. Two matches raise and write nothing, rather than
changing whichever came first: a partial edit is discovered later, by whoever reads the
document, which is the worst time to discover it. Include surrounding text to make the
match unique. If you really do mean the first of several, say so where it can be seen:
Search¶
search_full_text(query, n_results=10) returns a list of {"path", "content"} dicts, case-insensitive substring match:
store.search_full_text("inference")
# [{"path": "/notes/2026/q1.md", "content": "Focus on inference latency."}]
MemoryStore interface¶
DocumentStore also implements the abstract MemoryStore interface used by SemanticMemoryStore:
store(content)auto-assigns/note-{uuid}.mdand writessearch(query, n_results)wrapssearch_full_text()delete(identifier)treats the identifier as a path
This lets you swap the two stores in code that only needs the common interface.
Use as in-process agent tools¶
make_memory_tools(store) wraps the store as three @tool-decorated functions (store_memory, search_memories, and list_memories) that an agent can call directly without a separate MCP server process:
from aimu.memory import DocumentStore
from aimu.tools.builtin import make_memory_tools
from aimu.agents import Agent
import aimu
store = DocumentStore(persist_path="./doc_store")
agent = Agent(
aimu.client("anthropic:claude-sonnet-4-6"),
system_message="Use store_memory to save notes and search_memories to find them.",
tools=make_memory_tools(store),
)
agent.run("Save a note: the API deadline is June 15.")
agent.run("When is the API deadline?")
search_memories on a DocumentStore does case-insensitive full-text search (the same as search_full_text()), while on a SemanticMemoryStore it does vector similarity search. The agent interface is identical for both.
Pass the result to make_tools(..., memory_store=store) to combine memory with the full built-in tool set.
Path-based document tools¶
make_memory_tools exposes the generic MemoryStore interface (store / search / list). To give an agent the document store's richer path-based API, use make_document_tools(store), which returns save_document(path, content), read_document(path, max_lines=2000, offset=1), edit_document(path, old_str, new_str), list_documents(), and search_documents(query):
Because these tool names are distinct from make_memory_tools' (store_memory etc.), one agent can carry both: a SemanticMemoryStore for facts and a DocumentStore for documents. These are the in-process counterpart to the aimu.memory.document_mcp server below.
Reach for edit_document rather than save_document to change part of a document.
read_document returns a window of a long document and save_document replaces the whole
thing, so the read-modify-save round-trip would delete everything outside the window. It is
refused: save_document will not replace a document whose current text it has not shown the
model in full, so an agent that read one window gets an error naming edit_document instead
of a quietly truncated document.
A full read grants permission to replace; a truncated read takes it back; creating a new
document needs no read at all; and a document changed out-of-band after the read no longer
matches, so the permission lapses. The tracking is per make_document_tools(...) call and
in-process, so two agents over one store each answer for what they have read. A programmatic
caller is unaffected -- store.write() has no such guard, because the caller holds the
document and the tools exist to keep a model from discarding text it has never seen.
Expose as MCP tools¶
Registers memory_list, memory_search, memory_read, memory_write, memory_edit, memory_delete — AIMU's own names and parameters. They are not wire-compatible with Anthropic's memory tool (whose commands are view / create / str_replace / insert / delete / rename) or with its Managed Agents memory stores (id-addressed, and reached inside a session as a mounted filesystem). Unlike the in-process tools above, these raise rather than returning a message on a miss.
When to pick this vs semantic memory¶
- Use
DocumentStorewhen you want named locations (/preferences.md,/projects/x/spec.md) and substring search. Best for agent scratchpads, configuration, and structured notes. - Use
SemanticMemoryStorewhen you want fuzzy retrieval of small natural-language facts ("Paul lives in San Francisco" found by searching for "where is Paul"). Best for episodic memory.