ffs

July 13, 2026 ยท View on GitHub

ffs โ€” code-aware file search CLI for humans and AI agents

Release CI License Rust

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?

FeatureWhat it does
One binary to rule them allfind + grep + glob + cat + symbol + callers + refs in a single executable
Typo-tolerant by defaultQuery *.rs !test/ shcema works even with the typo
Frecency rankingFiles you open more often rank higher. Warm-up uses git touch history
Tree-sitter symbol indexAnswers code questions across 16 languages
Token-budget readerffs read path --budget 5000 clips body, preserves header and truncated footer
One warm processAfter first call, every subsequent query hits warm memory โ€” no per-call subprocess spawn
MCP server15-tool stdio JSON-RPC server for AI coding agents
C ABI (.so/.dylib/.dll)Stable foreign bindings for Python, Node.js, and more
zlib compressionOptional --features zlib for compressed indexes

How ffs Compares

Capabilityffsfind/fdgrep/rgglobcat
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 mcp resolves the root from, in order: WORKSPACE_FOLDER_PATHS (injected by Cursor/VS Code), VSCODE_CWD, then cwd. User-level ~/.cursor/mcp.json with args: ["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

PrincipleRationale
One binary to rule them allfind + grep + glob + cat + symbol + callers โ€” no pipelining, no format wars
Typo-tolerant by defaultFuzzy auto-detect query mode; shcema still finds the right file
Frecency rankingFiles you open more often rank higher; warm-up uses git touch history
Tree-sitter symbol indexAnswers code questions, not just file-name questions โ€” across 16 languages
Token-budget readerClips body but always preserves header + [truncated to budget] footer
One warm processAfter 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

CommandWhat it does
findFuzzy file-name search. Frecency-ranked, glob constraints, git-aware
globMatch files by glob pattern (replaces shell **)
grepContent search โ€” plain / regex / fuzzy auto-detect
multi-grepOR-logic multi-pattern literal search (Aho-Corasick; alias multigrep)
readToken-budget aware file read (replaces cat)
outlineStructural outline of a file (functions, classes, top-level decls)
symbolExact + prefix lookup over the tree-sitter symbol index
callersFind call sites of a symbol. Bloom-filter narrowed candidates
calleesSymbols referenced inside a symbol body
refsDefinitions + single-hop usages in one shot
flowDrill-down envelope per definition (def + body + callees + callers)
siblingsPeers of a symbol in its parent scope
depsA file's imports + files that depend on it
impactRank workspace files by change impact for a symbol
indexBuild / refresh on-disk indexes (Bigram, Bloom, Symbol, Outline)
mapWorkspace tree annotated with file count and per-directory tokens
overviewHigh-signal repo summary (languages, top symbols, entry-points)
mcpJSON-RPC MCP server over stdio (replaces agent built-in tools)
guideEmbedded agent guide

Performance

All numbers are single-threaded medians on Linux x86-64 (Criterion.rs).

Engine dispatch (256-file fixture)

Query typeMedian
Symbol lookup (worker_05_3)202 ns
Concept / NL query205 ns
File path (mod_03/file_2.rs)2.2 ยตs
Glob (**/*.rs)2.8 ยตs

Bigram index

Index size2-char query6-char query14-char query
10 K files46 ns120 ns314 ns
500 K files761 ns1.6 ยตs1.6 ยตs

Symbol index (1 K files)

OperationMedian
Index one Rust file (50 lines)219 ยตs
Exact symbol lookup95 ยต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

SymptomCauseFix
ffs index is slowFirst build โ€” expectedOne-time cost. Subsequent calls skip re-parse
Symbol queries return emptyIndex stale (git HEAD changed)Re-run ffs index
Fuzzy search unexpected resultsQuery too short (1 char)Add more characters or path qualifiers (src/)
MCP server not respondingServer process exitedKeep ffs mcp running as background service

Limitations

Edge caseReality
Pre-built index requiredRun ffs index once per repo. Index auto-invalidates on HEAD changes
16 languagesTree-sitter supports 16; non-listed languages fall back to text-only queries
Frecency needs gitWarm-up uses git touch history; without git, frecency starts cold
MCP stdio onlyffs 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.


One binary. All your code-search tools. <10ms warm.