
Memfs Search
- 100 installs
- 134 repo stars
- Updated July 3, 2026
- letta-ai/skills
Helps with ai & agent building tasks.
About
memfs-search is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- memfs-search
- AI & Agent Building
- AI-coding skill
Memfs Search by the numbers
- 100 all-time installs (skills.sh)
- +2 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #4,381 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/letta-ai/skills --skill memfs-searchAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 100 |
|---|---|
| repo stars | ★ 134 |
| Last updated | July 3, 2026 |
| Repository | letta-ai/skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
MemFS Search
Semantic search over your memory filesystem. Useful when Grep isn't enough — finding conceptually related blocks, discovering forgotten reference files, or answering "what do I know about X" across all memory.
Setup
First time only. Run the setup script to create the index and generate embeddings:
bash <SKILL_DIR>/scripts/memfs-search.sh setupThis creates a QMD collection over $MEMORY_DIR, adds context annotations, and embeds all .md files. First run downloads ~2GB of local GGUF models to ~/.cache/qmd/models/.
For installation, embedding model options, and troubleshooting: references/qmd-setup.md.
Searching
Three tiers. Pick based on what you know about your query:
| You have... | Use | Command | Speed |
|---|---|---|---|
| An exact term or phrase | keyword | search | ~0.3s |
| A vague concept ("what do I know about X") | semantic | vsearch | ~2s cold, <1s warm |
| No idea, need the best results | hybrid | query | ~3s cold, <1s warm |
S="bash <SKILL_DIR>/scripts/memfs-search.sh"
# Keyword — fast, use first
$S search "lettabot architecture"
# Semantic — conceptual, use when keyword misses
$S vsearch "how does the user feel about code reviews"
# Hybrid — best quality, uses keyword + vectors + reranking
$S query "projects cameron is working on"Always start with keyword search. Only escalate when it misses. Hybrid is 10x slower than keyword.
Output Formats
All commands accept output flags forwarded to QMD:
$S search "topic" --json # structured (for processing)
$S search "topic" --files # file paths only (pipe into Read)
$S search "topic" --full # full document, not snippet
$S search "topic" -n 15 # more results (default: 5)--json returns an array of objects with file, score, snippet, and context fields.
Retrieval
Fetch a specific file or batch of files without searching:
# Single file
qmd get "system/human/identity.md" -c memory --full
# Batch by glob
qmd multi-get "reference/projects/*" -c memoryWhen to Search Proactively
Don't wait to be asked. Search memory when:
1. Before creating a new memory file — check if the topic already exists. $S search "topic" --files tells you instantly. 2. User asks "do you know about X" — search before saying no. Reference files you haven't loaded recently might have it. 3. During `/init` or memory reorg — verify coverage. Search for key concepts and confirm they're stored somewhere. 4. Debugging "I told you about this" — the user thinks you should know something. Search memory before falling back to message history.
Maintenance
After bulk memory changes (e.g. after /init, reorganization, creating many files):
bash <SKILL_DIR>/scripts/memfs-search.sh reindexCheck index health:
bash <SKILL_DIR>/scripts/memfs-search.sh statusWhen NOT to Use
- Exact string matching — use Grep.
- Finding files by name/pattern — use Glob.
- Reading a file you already know the path to — use Read.
- Searching message history — use the
searching-messagesskill. - The query is a single word that would match literally — keyword Grep is faster.
MIT License
Copyright (c) 2026 Letta, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
QMD Setup
Install
# Node.js (recommended)
npm install -g @tobilu/qmd
# Or Bun
bun install -g @tobilu/qmd
# Or run without installing
npx @tobilu/qmd ...Requires Node.js >= 22. On macOS, also needs Homebrew SQLite (brew install sqlite).
First-Time Indexing
# Create collection pointing at your memory directory
qmd collection add "$MEMORY_DIR" --name memory --mask "**/*.md"
# Add context to improve search relevance
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 vector embeddings (downloads ~2GB of GGUF models on first run)
qmd embedFirst qmd embed downloads three local models (~2GB total) to ~/.cache/qmd/models/. Subsequent runs are fast.
Embedding Models
QMD embeds locally using bundled GGUF models. No API keys needed.
| Model | Env/Flag | Size | Notes |
|---|---|---|---|
| embeddinggemma-300M | default | ~328MB | English-optimized, small footprint |
| Qwen3-Embedding-0.6B | QMD_EMBED_MODEL | ~640MB | Multilingual (119 languages) |
# Switch to Qwen3 for multilingual support
export QMD_EMBED_MODEL="hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf"
qmd embed -f # re-embed with new model (vectors aren't cross-compatible)No cloud embedding providers (OpenAI, etc.) are supported yet. Gemini support is in-progress upstream (tobi/qmd#365).
Important: When switching embedding models, always re-embed with qmd embed -f — vectors from different models are not compatible.
Verify
qmd status
qmd search "test query" -c memoryRe-Indexing
Run after bulk memory changes (e.g. after /init, memory reorganization, or creating many new files):
qmd update && qmd embedTroubleshooting
"No collections configured": Run qmd collection add "$MEMORY_DIR" --name memory
Slow first search: Models are loading into memory. Subsequent searches are fast. Use qmd mcp --http --daemon for a persistent server.
SQLite errors / sqlite-vec crash on macOS: brew install sqlite and retry. If BUN_INSTALL is set in your env, QMD's launcher will use Bun instead of Node — Bun's SQLite doesn't support extension loading. Fix: unset BUN_INSTALL before running QMD, or install via npm (not bun).
#!/usr/bin/env bash
# memfs-search — semantic search over agent memory files
#
# Usage:
# memfs-search setup Initialize backend and index memory
# memfs-search search <query> Keyword search (BM25)
# memfs-search vsearch <query> Semantic vector search
# memfs-search query <query> Hybrid search (best quality)
# memfs-search status Show index health
# memfs-search reindex Re-index after memory changes
#
# Environment:
# MEMORY_DIR Agent memory directory (required)
# MEMFS_BACKEND Force backend: qmd (default: auto-detect)
# QMD_EMBED_MODEL Override QMD embedding model
#
# All extra arguments are forwarded to the underlying backend.
set -euo pipefail
# --- Configuration -----------------------------------------------------------
COLLECTION_NAME="memory"
MASK="**/*.md"
# --- Helpers ------------------------------------------------------------------
die() { echo "error: $*" >&2; exit 1; }
info() { echo ":: $*" >&2; }
detect_backend() {
if [ -n "${MEMFS_BACKEND:-}" ]; then
echo "$MEMFS_BACKEND"
return
fi
if command -v qmd &>/dev/null; then
echo "qmd"
return
fi
echo "none"
}
require_memory_dir() {
[ -n "${MEMORY_DIR:-}" ] || die "MEMORY_DIR is not set"
[ -d "$MEMORY_DIR" ] || die "MEMORY_DIR does not exist: $MEMORY_DIR"
}
# --- QMD Backend --------------------------------------------------------------
qmd_cmd() {
# Ensure Node runtime (Bun's sqlite doesn't support extensions)
unset BUN_INSTALL 2>/dev/null || true
# Prefer the Node binary next to the qmd executable. Cameron's machine can
# have a broken Homebrew node earlier in PATH, while qmd is installed under
# nvm with a working Node runtime.
local qmd_bin qmd_dir
qmd_bin="$(command -v qmd)"
qmd_dir="$(dirname "$qmd_bin")"
if [ -x "$qmd_dir/node" ]; then
PATH="$qmd_dir:$PATH" command qmd "$@"
else
command qmd "$@"
fi
}
qmd_setup() {
require_memory_dir
info "Setting up QMD backend..."
# Create collection if it doesn't exist
if ! qmd_cmd collection list 2>/dev/null | grep -q "^$COLLECTION_NAME"; then
qmd_cmd collection add "$MEMORY_DIR" --name "$COLLECTION_NAME" --mask "$MASK"
else
info "Collection '$COLLECTION_NAME' already exists"
fi
# Add context annotations
qmd_cmd context add "qmd://$COLLECTION_NAME" \
"Agent memory blocks — system prompt files and reference materials" 2>/dev/null || true
qmd_cmd context add "qmd://$COLLECTION_NAME/system" \
"In-context memory blocks rendered in the system prompt every turn" 2>/dev/null || true
qmd_cmd context add "qmd://$COLLECTION_NAME/reference" \
"Reference materials loaded on-demand via tools" 2>/dev/null || true
# Generate embeddings
info "Generating embeddings..."
qmd_cmd embed
info "Setup complete. Run 'memfs-search status' to verify."
}
qmd_search() { qmd_cmd search "$@" -c "$COLLECTION_NAME"; }
qmd_vsearch() { qmd_cmd vsearch "$@" -c "$COLLECTION_NAME"; }
qmd_query() { qmd_cmd query "$@" -c "$COLLECTION_NAME"; }
qmd_status() { qmd_cmd status; }
qmd_reindex() {
require_memory_dir
info "Re-indexing memory..."
qmd_cmd update
qmd_cmd embed
info "Done."
}
# --- Dispatch -----------------------------------------------------------------
BACKEND=$(detect_backend)
CMD="${1:-help}"
shift || true
case "$CMD" in
setup)
case "$BACKEND" in
qmd) qmd_setup "$@" ;;
none) die "No backend available. Install QMD: npm install -g @tobilu/qmd" ;;
*) die "Unknown backend: $BACKEND" ;;
esac
;;
search)
[ $# -ge 1 ] || die "Usage: memfs-search search <query> [options]"
case "$BACKEND" in
qmd) qmd_search "$@" ;;
none) die "No backend available. Run 'memfs-search setup' first." ;;
*) die "Unknown backend: $BACKEND" ;;
esac
;;
vsearch)
[ $# -ge 1 ] || die "Usage: memfs-search vsearch <query> [options]"
case "$BACKEND" in
qmd) qmd_vsearch "$@" ;;
none) die "No backend. Semantic search requires QMD: npm install -g @tobilu/qmd" ;;
*) die "Unknown backend: $BACKEND" ;;
esac
;;
query)
[ $# -ge 1 ] || die "Usage: memfs-search query <query> [options]"
case "$BACKEND" in
qmd) qmd_query "$@" ;;
none) die "No backend. Hybrid search requires QMD: npm install -g @tobilu/qmd" ;;
*) die "Unknown backend: $BACKEND" ;;
esac
;;
status)
case "$BACKEND" in
qmd) qmd_status "$@" ;;
none) echo "backend: none"; echo "No search backend configured." ;;
*) die "Unknown backend: $BACKEND" ;;
esac
;;
reindex)
case "$BACKEND" in
qmd) qmd_reindex "$@" ;;
none) die "No backend available. Run 'memfs-search setup' first." ;;
*) die "Unknown backend: $BACKEND" ;;
esac
;;
help|--help|-h)
echo "Usage: memfs-search <command> [args...]"
echo ""
echo "Commands:"
echo " setup Initialize backend and index memory"
echo " search <query> Keyword search (BM25, fast)"
echo " vsearch <query> Semantic vector search"
echo " query <query> Hybrid search (best quality)"
echo " status Show index health"
echo " reindex Re-index after memory changes"
echo ""
echo "Backend: $BACKEND"
echo ""
echo "Extra arguments are forwarded to the backend (e.g. -n 10, --json, --files)."
;;
*)
die "Unknown command: $CMD. Run 'memfs-search help' for usage."
;;
esac