Letta Code MemFS Search Mod#
A portable Letta Code mod that exposes an agent-callable memfs_search tool for searching the current agent's MemFS memory files.
MemFS is the local filesystem projection of an agent's memory. This mod lets an agent search that projection from inside Letta Code without shelling out manually. It is useful when the agent needs to answer questions like "what do you know about X?", find existing memory before writing new memory, or locate relevant reference files.
Features#
- Agent-callable
memfs_searchtool. - Built-in keyword search over local markdown memory files.
- Optional QMD-backed semantic and hybrid search.
- QMD compatibility safeguards for QMD 2.5.x:
- semantic/hybrid use structured queries
--no-rerankavoids surprise query-expansion/reranker model downloads- files-only output auto-detects
--filesvs--format files
- Memory directory auto-detection from
MEMORY_DIRor common local Letta paths. - Status action for diagnostics.
- No API keys required.
Repository layout#
mods/memfs-search.mjs # Letta Code mod
README.md # This guide
LICENSE # MIT
Install#
Copy the mod into the Letta Code mods directory:
mkdir -p ~/.letta/mods
cp mods/memfs-search.mjs ~/.letta/mods/memfs-search.mjs
Then reload Letta Code mods:
/reload
If a mod breaks startup or command handling, start Letta Code with mods disabled:
LETTA_DISABLE_MODS=1 letta
# or
letta --no-mods
Then remove or edit the mod file under ~/.letta/mods/.
Quick start#
After install and /reload, ask the agent to search memory, or call the tool directly:
{
"query": "commit footer preferences",
"mode": "keyword",
"limit": 5
}
Check diagnostics:
{ "action": "status" }
Example status output:
MEMORY_DIR: /Users/me/.letta/lc-local-backend/memfs/agent-.../memory
exists: yes
qmd: available
markdown_files: 70
Tool reference#
Tool name:
memfs_search
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
action |
search or status |
search |
Use status to inspect memory path and QMD availability. |
query |
string | required for search | Search query. |
mode |
keyword, semantic, hybrid |
keyword |
Search backend/method. |
limit |
number | 8 |
Maximum results. Clamped to 50. |
files_only |
boolean | false |
Return only matching file paths. |
full |
boolean | false |
Return larger/full file content snippets. |
Search modes#
keyword#
Built in. No dependencies. Searches local markdown files directly.
Use this first when you have exact terms, names, paths, project names, phrases, or other literal clues.
{
"query": "The Coil preferences",
"mode": "keyword",
"limit": 5
}
The keyword scorer prefers:
- exact phrase matches
- files matching more distinct query terms
- path matches
- core
system/memory when scores are close - shorter focused files when scores are close
semantic#
Requires QMD setup and embeddings. Uses vector search through a structured QMD query:
qmd query "vec: <query>" -c memory -n <limit> --no-rerank
Use this when you only have a vague concept and keyword search misses.
{
"query": "how does Cameron like agents to handle long context summaries",
"mode": "semantic",
"limit": 5
}
hybrid#
Requires QMD setup and embeddings. Uses both lexical and vector search through a structured QMD query:
qmd query $'lex: <query>\nvec: <query>' -c memory -n <limit> --no-rerank
Use this when you want better recall than keyword but still want lexical matches included.
{
"query": "agent profile image",
"mode": "hybrid",
"limit": 10
}
Why structured QMD queries?#
QMD 2.5.x can run query expansion or reranking for some commands, including plain qmd query and in practice qmd vsearch on some setups. That can trigger a large model download, for example a ~1.28 GB query-expansion GGUF file, which is not appropriate inside a short mod tool call.
This mod avoids that by using structured QMD query documents and --no-rerank:
# semantic
qmd query "vec: <query>" --no-rerank
# hybrid
qmd query $'lex: <query>\nvec: <query>' --no-rerank
That keeps searches on already-installed BM25/vector indexes and avoids surprise expansion/reranker downloads.
QMD setup#
Keyword mode works without QMD. Semantic and hybrid modes need QMD installed and indexed.
Install QMD:
npm install -g @tobilu/qmd
# or
bun install -g @tobilu/qmd
QMD currently needs a working Node runtime. On macOS, if SQLite native modules fail, install/rebuild under the Node version that runs QMD.
Create a memory collection:
qmd collection add "$MEMORY_DIR" --name memory --mask "**/*.md"
Add helpful context annotations:
qmd context add qmd://memory "Agent memory blocks — system prompt files and reference materials"
qmd context add qmd://memory/system "In-context memory blocks rendered in the system prompt every turn"
qmd context add qmd://memory/reference "Reference materials loaded on-demand via tools"
Generate embeddings:
qmd embed
First embed may download local embedding models. This is normal QMD setup work and should be done outside a mod tool call.
Verify:
qmd status
qmd search "test query" -c memory
qmd query "vec: test query" -c memory --no-rerank
Memory path detection#
The mod resolves the memory directory in this order:
MEMORY_DIR, if set and existing.~/.letta/lc-local-backend/memfs/<agent-id>/memory~/.letta/agents/<agent-id>/memory
The agent id comes from the mod context (ctx.agent.id) or AGENT_ID.
If no memory path exists, action=status will show the attempted path and exists: no.
Examples#
Status#
{ "action": "status" }
Keyword search#
{
"query": "supervillain project architecture",
"mode": "keyword",
"limit": 5
}
Files only#
{
"query": "profile image",
"mode": "keyword",
"files_only": true
}
Fuller snippets#
{
"query": "Cameron preferences",
"mode": "keyword",
"full": true,
"limit": 3
}
Semantic search#
{
"query": "what does the user care about in coding agents",
"mode": "semantic",
"limit": 5
}
Hybrid search#
{
"query": "Signal channel debugging",
"mode": "hybrid",
"limit": 8
}
Privacy and safety#
This is trusted local code. It reads markdown files from the current agent's local memory filesystem projection and returns matching snippets/paths to the model.
It does not:
- send memory to a cloud API
- require API keys
- mutate memory files
- commit or push memory changes
Semantic and hybrid modes call local QMD. QMD embedding/search is local, but QMD may download local model files during setup. This mod is designed to avoid triggering large query-expansion/reranker downloads during search.
Troubleshooting#
MEMORY_DIR is not set or does not exist#
Run:
{ "action": "status" }
Check whether the inferred path exists. If not, set MEMORY_DIR before launching Letta Code or update the mod's fallback paths for your backend layout.
qmd: not found#
Keyword mode still works. For semantic/hybrid:
npm install -g @tobilu/qmd
qmd collection add "$MEMORY_DIR" --name memory --mask "**/*.md"
qmd embed
Then reload Letta Code:
/reload
QMD tries to download a huge query-expansion or reranker model#
Update this mod. Versions after commit 98e7ff2 use structured queries plus --no-rerank to avoid that behavior.
If you already have a partial .ipull download from a failed run, it is safe to remove the partial file from QMD's model/cache directory if QMD is not currently running.
QMD native SQLite / Node mismatch#
Symptoms may include errors like:
better_sqlite3.node was compiled against a different Node.js version
The mod tries to prefer the Node binary next to the qmd executable by prepending QMD's bin directory to PATH and unsetting BUN_INSTALL. If errors persist, reinstall or rebuild QMD under the Node version used to run QMD:
npm rebuild -g @tobilu/qmd
# or reinstall
npm install -g @tobilu/qmd
Semantic/hybrid returns no results but keyword works#
Check QMD index health:
qmd status
qmd collection list
qmd embed
Try a direct structured query:
qmd query "vec: commit footer preferences" -c memory --no-rerank
If this returns no results, QMD embeddings/indexing need attention, not the mod.
files_only returns weird output#
QMD versions differ. Some support --files; some document --format files. The mod auto-detects by inspecting qmd query --help. If output is still odd, run:
qmd query --help
and check the available output flags.
Development#
Validate syntax:
node --check mods/memfs-search.mjs
Install locally from this repo:
cp mods/memfs-search.mjs ~/.letta/mods/memfs-search.mjs
Reload Letta Code:
/reload
Manual smoke test from a Node script:
node - <<'NODE'
import mod from './mods/memfs-search.mjs';
let tool;
mod({ capabilities: { tools: true }, tools: { register(def) { tool = def; return () => {}; } } });
console.log(await tool.run({
cwd: process.cwd(),
agent: { id: process.env.AGENT_ID },
args: { action: 'status' },
signal: AbortSignal.timeout(10000),
}));
NODE
Limitations#
- Only markdown files (
*.md) are searched. - Keyword mode is simple local scoring, not a full search engine.
- Semantic/hybrid modes depend on QMD being installed, configured, and embedded.
- The mod is read-only; it does not write or reorganize memory.
- It searches memory files, not conversation history/recall memory.
Roadmap#
Possible future improvements:
- Slash command wrapper for manual
/memfs-searchusage. - Optional commands for QMD setup/status/reindex.
- Better structured JSON output mode.
- More robust QMD version detection.
- Searching non-markdown memory assets where appropriate.