ffs
July 13, 2026 ยท View on GitHub
A code-aware file search CLI for humans and AI agents. Really fast.
Replaces find + grep + glob + cat + tree-sitter with one binary. Typo-tolerant fuzzy matching, frecency ranking, token-budget reader, MCP server.
curl -fsSL "https://raw.githubusercontent.com/quangdang46/fast_file_search/main/install.sh?$(date +%s)" | bash
๐ค Agent Quickstart (MCP / Robot Mode)
ffs ships a 15-tool MCP server over stdio. The installer auto-configures it for Claude Code, Codex, Cursor, Windsurf, Gemini, OpenCode, and more.
# Run as MCP server
ffs mcp
# Agent-friendly JSON queries
ffs grep 'fn main' --format json
ffs symbol FilePicker --format json
ffs read crates/ffs-engine/src/lib.rs --budget 5000 --format json
ffs map --depth 3 --format json
ffs overview --format json
ffs deps path/to/file.rs --format json
Output conventions
- stdout = structured data (JSON or text)
- stderr = diagnostics, warnings
- exit 0 = success
MCP tools exposed: ffs_find, ffs_grep, ffs_multi_grep, ffs_symbol, ffs_callers, ffs_callees, ffs_refs, ffs_flow, ffs_impact, ffs_outline, ffs_siblings, ffs_deps, ffs_map, ffs_overview, ffs_read
TL;DR
The Problem
File search and code navigation require a menagerie of tools: find, fd, grep, rg, glob, cat, plus a tree-sitter plugin for symbol queries. Each has different syntax, different startup cost, different output formats. AI agents struggle with this combinatorial explosion of invocation patterns โ and every pipeline hop loses milliseconds that add up across hundreds of queries.
The Solution
ffs replaces all of them with a single binary that understands code. Typo-resistant fuzzy matching, frecency-ranked results, tree-sitter-powered symbol/callers/callees/refs queries, and a token-budget aware file reader โ all from one executable that starts in milliseconds and keeps a warm cache for sub-10 ms subsequent calls.
Why ffs?
| Feature | What it does |
|---|---|
| One binary to rule them all | find + grep + glob + cat + symbol + callers + refs in a single executable |
| Typo-tolerant by default | Query *.rs !test/ shcema works even with the typo |
| Frecency ranking | Files you open more often rank higher. Warm-up uses git touch history |
| Tree-sitter symbol index | Answers code questions across 16 languages |
| Token-budget reader | ffs read path --budget 5000 clips body, preserves header and truncated footer |
| One warm process | After first call, every subsequent query hits warm memory โ no per-call subprocess spawn |
| MCP server | 15-tool stdio JSON-RPC server for AI coding agents |
| C ABI (.so/.dylib/.dll) | Stable foreign bindings for Python, Node.js, and more |
| zlib compression | Optional --features zlib for compressed indexes |
How ffs Compares
| Capability | ffs | find/fd | grep/rg | glob | cat |
|---|---|---|---|---|---|
| File-name search (fuzzy, frecency) | โ | โ /โ | โ | โ | โ |
| Content grep (SIMD, typo-tolerant) | โ | โ | โ /โ | โ | โ |
| Symbol lookup (tree-sitter) | โ | โ | โ | โ | โ |
| Callers / callees / refs | โ | โ | โ | โ | โ |
| Token-budget file reader | โ | โ | โ | โ | โ |
| MCP server | โ 15 tools | โ | โ | โ | โ |
| Single process, warm cache | โ | โ | โ | โ | โ |
| Globbing | โ | โ | โ | โ | โ |
Quick Example
# Index once, query forever
ffs index # ~200 ms on 10k-file repo
ffs find UnifiedScanner # fuzzy file-name search
ffs find grep --scored # role-aware ranking
ffs grep '\bTODO\b' --root crates/ # content grep
ffs grep 'fn main' --group # symbol-grouped grep
ffs multi-grep TODO FIXME HACK # multi-literal OR (Aho-Corasick)
ffs symbol FilePicker # tree-sitter symbol lookup
ffs callers UnifiedScanner # who calls a symbol
ffs read crates/ffs-engine/src/lib.rs --budget 5000 # token-budget reader
ffs map --depth 3 # workspace tree
ffs mcp # run as MCP server over stdio
ffs mcp /path/to/workspace # pin MCP index root explicitly
MCP workspace root. When launched without a path (as installers do for Cursor/VS Code),
ffs mcpresolves the root from, in order:WORKSPACE_FOLDER_PATHS(injected by Cursor/VS Code),VSCODE_CWD, thencwd. User-level~/.cursor/mcp.jsonwithargs: ["mcp"]therefore indexes the open workspace, not the home directory. Prefer an explicit path (args: ["mcp", "${workspaceFolder}"]) in project-level configs when available.
Design Philosophy
| Principle | Rationale |
|---|---|
| One binary to rule them all | find + grep + glob + cat + symbol + callers โ no pipelining, no format wars |
| Typo-tolerant by default | Fuzzy auto-detect query mode; shcema still finds the right file |
| Frecency ranking | Files you open more often rank higher; warm-up uses git touch history |
| Tree-sitter symbol index | Answers code questions, not just file-name questions โ across 16 languages |
| Token-budget reader | Clips body but always preserves header + [truncated to budget] footer |
| One warm process | After first call, every subsequent query hits warm memory โ no per-call subprocess spawn |
Installation
# macOS / Linux โ curl pipe
curl -fsSL "https://raw.githubusercontent.com/quangdang46/fast_file_search/main/install.sh?$(date +%s)" | bash
# Windows PowerShell
irm https://raw.githubusercontent.com/quangdang46/fast_file_search/main/install.ps1 | iex
# From source (with zlib compression support)
cargo build --release -p ffs-cli --features zlib
./target/release/ffs --version
The installers detect platform, fetch the matching release binary, verify SHA-256 sidecar, and atomically install to ~/.local/bin/ffs. MCP server configs are auto-detected for Claude Code, Codex, Cursor, Windsurf, VS Code, Gemini, OpenCode, and more.
Supported platforms
Linux x86_64/aarch64, macOS x86_64/aarch64, Windows x86_64/aarch64
Commands
| Command | What it does |
|---|---|
find | Fuzzy file-name search. Frecency-ranked, glob constraints, git-aware |
glob | Match files by glob pattern (replaces shell **) |
grep | Content search โ plain / regex / fuzzy auto-detect |
multi-grep | OR-logic multi-pattern literal search (Aho-Corasick; alias multigrep) |
read | Token-budget aware file read (replaces cat) |
outline | Structural outline of a file (functions, classes, top-level decls) |
symbol | Exact + prefix lookup over the tree-sitter symbol index |
callers | Find call sites of a symbol. Bloom-filter narrowed candidates |
callees | Symbols referenced inside a symbol body |
refs | Definitions + single-hop usages in one shot |
flow | Drill-down envelope per definition (def + body + callees + callers) |
siblings | Peers of a symbol in its parent scope |
deps | A file's imports + files that depend on it |
impact | Rank workspace files by change impact for a symbol |
index | Build / refresh on-disk indexes (Bigram, Bloom, Symbol, Outline) |
map | Workspace tree annotated with file count and per-directory tokens |
overview | High-signal repo summary (languages, top symbols, entry-points) |
mcp | JSON-RPC MCP server over stdio (replaces agent built-in tools) |
guide | Embedded agent guide |
Performance
All numbers are single-threaded medians on Linux x86-64 (Criterion.rs).
Engine dispatch (256-file fixture)
| Query type | Median |
|---|---|
Symbol lookup (worker_05_3) | 202 ns |
| Concept / NL query | 205 ns |
File path (mod_03/file_2.rs) | 2.2 ยตs |
Glob (**/*.rs) | 2.8 ยตs |
Bigram index
| Index size | 2-char query | 6-char query | 14-char query |
|---|---|---|---|
| 10 K files | 46 ns | 120 ns | 314 ns |
| 500 K files | 761 ns | 1.6 ยตs | 1.6 ยตs |
Symbol index (1 K files)
| Operation | Median |
|---|---|
| Index one Rust file (50 lines) | 219 ยตs |
| Exact symbol lookup | 95 ยตs |
Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Frontends โ
โ ffs-cli (binary) ยท ffs-mcp (MCP) โ
โ ffs-c (C ABI .so/.dylib/.dll) โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ
โ all surfaces share one core
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Engine layer โ
โ ffs-engine โ dispatch ยท ranking โ
โ ffs-query-parser โ DSL + constraints โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Capability layer โ
โ ffs-symbol โ tree-sitter ยท bloom โ
โ ffs-grep โ SIMD literal / regex โ
โ ffs-budget โ token-aware reader โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Core layer (ffs-core) โ
โ scan ยท file_picker ยท score ยท git โ
โ frecency ยท watcher ยท ignore โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
ffs index is slow | First build โ expected | One-time cost. Subsequent calls skip re-parse |
| Symbol queries return empty | Index stale (git HEAD changed) | Re-run ffs index |
| Fuzzy search unexpected results | Query too short (1 char) | Add more characters or path qualifiers (src/) |
| MCP server not responding | Server process exited | Keep ffs mcp running as background service |
Limitations
| Edge case | Reality |
|---|---|
| Pre-built index required | Run ffs index once per repo. Index auto-invalidates on HEAD changes |
| 16 languages | Tree-sitter supports 16; non-listed languages fall back to text-only queries |
| Frecency needs git | Warm-up uses git touch history; without git, frecency starts cold |
| MCP stdio only | ffs mcp speaks JSON-RPC over stdio โ no HTTP/WebSocket transport (yet) |
FAQ
Does ffs need a pre-built index?
Yes โ run ffs index once per repo. The index is cached in <repo>/.ffs/ and auto-invalidates on schema bumps, git HEAD changes, or significant file-count drift.
Can I use ffs as a library from Rust?
Yes โ all crates publish via ffs-*. The C ABI (ffs-c) is stable for foreign bindings (Python, Node.js, etc.).
What's the difference between ffs callers and ffs refs?
callers lists call sites (who invokes a symbol). refs combines definitions and usages in one shot โ both call sites and other references.
Does ffs work on non-git directories?
Yes โ it falls back to a full filesystem scan. Some features (frecency warm-up, cache invalidation) require git.
MCP vs CLI โ which should agents use?
Prefer ffs mcp for agent contexts โ 15 tools via stdio JSON-RPC, no parsing required. Use CLI with --format json for one-shot queries.