使用说明
vfs
Extract exported function signatures with bodies stripped -- cutting 60-70% of the tokens your AI agent reads on every code search.
Install • Quick Start • Commands • Setup for AI Tools • Supported Languages • Security & Privacy
vfs parses source files via AST and tree-sitter and returns only exported signatures -- a compact "table of contents" of any codebase. One command (or one MCP call) replaces grep-and-read-everything with exact file:line pointers. Single Go binary, zero network access, works with any AI tool.
What VFS Does
| Instead of | vfs returns |
|---|---|
grep -r "HandleLogin" . → 345 lines of matches |
21 signature lines |
| Reading 7,979 lines to find one function | auth.go:23: func HandleLogin(w http.ResponseWriter, r *http.Request) |
| ~48,757 tokens of context | ~570 tokens |
How Savings Work
vfs measures bytes of source that reach the model, estimated as bytes / 4. Bodies are stripped at parse time, so a function that costs 50 lines of context costs one line. The savings are real but the absolute token numbers are approximate -- vfs ships no tokenizer.
On this repository (vfs bench --self, pattern "Extract"):
| Read all files | grep | vfs | |
|---|---|---|---|
| Output size | 190.5 KB | 47.5 KB | 2.2 KB |
| Lines | 7,979 | 345 | 21 |
| Est. tokens | 48,757 | 12,154 | 570 |
- 98.8% fewer tokens vs reading all files (48,757 → 570)
- 95.3% fewer tokens vs grep (12,154 → 570)
These are reductions in context tokens, not in your bill -- but for a tool your agent runs on every search, they add up fast.
Installation
Pre-built binary (Linux -- nothing else needed)
# x86_64
curl -L https://github.com/TrNgTien/vfs/releases/latest/download/vfs-linux-amd64.tar.gz | tar xz
sudo mv vfs /usr/local/bin/
# ARM64
curl -L https://github.com/TrNgTien/vfs/releases/latest/download/vfs-linux-arm64.tar.gz | tar xz
sudo mv vfs /usr/local/bin/
Build from source (macOS / Linux / Windows)
Requires Go 1.24+ and a C compiler (tree-sitter C bindings):
| OS | Command |
|---|---|
| macOS | xcode-select --install |
| Linux (Debian/Ubuntu) | sudo apt install build-essential |
| Linux (Fedora/RHEL) | sudo yum groupinstall "Development Tools" |
| Windows | Install TDM-GCC (easiest) or MSYS2 + MinGW-w64 |
git clone https://github.com/TrNgTien/vfs.git && cd vfs
go install ./cmd/vfs
vfs: command not foundafter install? Add Go's bin to PATH:export PATH="$PATH:$(go env GOPATH)/bin"(macOS/Linux) or add%USERPROFILE%\go\binto PATH (Windows).
Docker (any OS)
docker build -t vfs-mcp .
docker run --rm -v $(pwd):/workspace -p 8080:8080 -p 3000:3000 vfs-mcp
# Custom ports via environment variables
docker run --rm -v $(pwd):/workspace -e VFS_PORT=9090 -e VFS_DASHBOARD_PORT=4000 -p 9090:9090 -p 4000:4000 vfs-mcp
Verify Installation
vfs . -f HandleLogin # Should show signatures, not an error
vfs bench --self # Should show the savings table
Quick Start
# Find a function by name (case-insensitive)
vfs . -f HandleLogin
# List all signatures in a directory or file
vfs ./internal ./pkg
vfs server.go
# Show token savings after output
vfs . -f auth --stats
# Start the MCP server + dashboard (detached)
vfs up
# Check / stop it
vfs status
vfs down
Then open the dashboard at http://localhost:3000 for usage stats over time.
How It Works
Without vfs: With vfs:
Agent --grep "HandleLogin"--> shell Agent --vfs search--> vfs (AST)
^ | ^ |
| 345 lines of matches | | 2 sigs, ~570 tokens |
+--------------------------------+ +--- file:line + signature -+
Four properties make the savings work:
- AST parsing - understands structure, not just text. Finds
class User,type User struct,func (u *User) Login, not just string matches. - Bodies stripped - you get the signature, not the 50 lines underneath it.
- Case-insensitive filter - one search finds
fare,Fare, andFARE. - Token accounting - every invocation is measured and reported (
--stats,vfs stats, dashboard).
The companion rule in this repo (.cursor/rules/vfs-agent-search.mdc) teaches agents when to use vfs (locate/understand/modify) vs grep (debug, string literals, callers) -- see Setup for AI Tools.
Commands
Search
vfs . # All exported signatures (recursive)
vfs ./src ./lib # Multiple directories
vfs handler.go # Single file
vfs . -f auth # Case-insensitive filter
vfs . -f auth --stats # + token savings report
vfs . -f auth --no-record # Skip history logging
Benchmarks
vfs bench --self # Self-test on vfs source
vfs bench -f HandleLogin /path/to/project # Benchmark any project
vfs bench -f Login /path --show-output # Show actual grep/vfs output
Statistics
vfs stats # Lifetime token savings
vfs stats --json # JSON export for dashboards/CI
vfs stats --reset # Clear all history
MCP Server
vfs mcp # stdio transport (default, editor integration)
vfs mcp --http :8080 # HTTP transport (Docker / remote)
vfs serve # MCP + dashboard, foreground
vfs serve --port 9090 --dashboard-port 4000 # custom ports
vfs up # Same, detached (background)
vfs status # Is it running? show endpoints
vfs down # Stop the detached server
vfs dashboard # Dashboard UI only
MCP tools exposed: search, extract, list_languages.
Global Flags
| Flag | Description |
|---|---|
-f, --filter |
Case-insensitive substring filter on signature names |
--stats |
Print token savings (raw vs vfs) to stderr |
--no-record |
Skip logging this invocation to ~/.vfs/history.jsonl |
--version |
Show version, commit, and build date |
Examples
"Where is the login handler?"
# Without vfs: grep + read
grep -r "HandleLogin" . # 345 lines of matches
cat auth.go # then read the whole file
# With vfs
vfs . -f login
→ internal/handlers/auth.go:23: func HandleLogin(w http.ResponseWriter, r *http.Request)
→ internal/services/auth.go:10: func ValidateToken(token string) (*Claims, error)
→ internal/middleware/jwt.go:45: func RequireLogin(next http.Handler) http.Handler
Multi-language project:
vfs . -f user
→ internal/services/user.go:42: func CreateUser(name string, email string) (*User, error)
→ src/hooks/useUser.ts:8: export function useUser(id: string): UserState
→ app/models/user.py:15: class User(BaseModel)
→ src/api/UserService.java:22: public class UserService
→ contracts/UserRegistry.sol:10: contract UserRegistry is Ownable { ... }
When grep IS the right tool -- vfs finds definitions, not bodies, callers, or config keys:
grep "INVALID_API_KEY" ./internal/ # string literal inside a function body
grep "database_url" ./*.yaml # non-code file
grep "CalculateFare" ./internal/ # who CALLS it (vfs finds the definition)
Setup for AI Tools
Two steps -- both required:
- Connect vfs -- make it reachable from the agent (MCP preferred, CLI fallback).
- Add an agent rule -- tell the agent it should call vfs before grep. Without the rule, the agent ignores vfs even when installed.
Step 1: Connect vfs
| Method | How it works | Best for |
|---|---|---|
| MCP (recommended) | Agent calls search / extract / list_languages directly |
Editors with MCP support (most modern AI tools) |
| CLI | Agent runs vfs <path> -f <pattern> via shell |
Terminal tools, scripts, sandboxed-free environments |
Stdio config (Cursor, Claude Code, Claude Desktop, Antigravity, Windsurf, Cline):
{
"mcpServers": {
"vfs": {
"command": "vfs",
"args": ["mcp"]
}
}
}
Claude Code (preferred): claude mcp add vfs -- vfs mcp -- registers in ~/.claude.json.
Continue:
{
"experimental": {
"modelContextProtocolServers": [
{ "transport": { "type": "stdio", "command": "vfs", "args": ["mcp"] } }
]
}
}
Zed:
{
"context_servers": {
"vfs": { "command": { "path": "vfs", "args": ["mcp"] } }
}
}
HTTP config (Docker, remote, or tools that prefer HTTP):
vfs up # MCP on :8080, dashboard on :3000
vfs up --port 9090
{
"mcpServers": { "vfs": { "url": "http://localhost:8080/mcp" } }
}
Step 2: Add an agent rule (required)
Installing vfs is not enough -- agents don't know it exists. This repo ships a production-ready rule at .cursor/rules/vfs-agent-search.mdc, and a one-command installer to put it into your tool:
./scripts/install-rules.sh # auto-detect your AI tool
./scripts/install-rules.sh --agent cursor # install for one tool
./scripts/install-rules.sh --agent all # every tool
./scripts/install-rules.sh --project ../myapp --agent claude # another project
./scripts/install-rules.sh --list # supported tools + paths
Same via Make: make rules or make rules RULES_ARGS="--agent windsurf --project ../myapp".
The installer is idempotent and safe: plain-markdown tools (Claude Code, Cline, Aider, Antigravity) get the rule appended under a ## vfs: heading -- your existing config is never overwritten -- while frontmatter tools (Cursor, Windsurf, Continue, OpenCode) get a verbatim copy.
| Tool | Rule file | Notes |
|---|---|---|
| Cursor | .cursor/rules/vfs.mdc |
Copy of .mdc (frontmatter kept) |
| Claude Code | CLAUDE.md |
Appended, frontmatter stripped |
| Antigravity | GEMINI.md |
Appended, frontmatter stripped; also reads AGENTS.md |
| Windsurf | .windsurf/rules/vfs.md |
Copy of .mdc |
| Cline / Roo Code | .clinerules |
Appended, frontmatter stripped |
| Continue | .continue/rules/vfs.md |
Copy of .mdc |
| Aider | .aider.conventions.md |
Appended, frontmatter stripped |
| OpenCode | .opencode/rules/vfs.mdc |
Copy of .mdc |
Without the rule, this is what happens:
You: "Where is the login handler?"
❌ No rule: Agent greps + reads → 345 lines → 12,000+ tokens
✅ With rule: Agent calls vfs → reads 23 lines → ~570 tokens
Supported Languages
| Language | Extensions | Parser |
|---|---|---|
| Go | .go |
go/ast |
| JavaScript | .js, .mjs, .cjs, .jsx |
tree-sitter |
| TypeScript | .ts, .mts, .cts, .tsx |
tree-sitter |
| Python | .py |
tree-sitter |
| Rust | .rs |
tree-sitter |
| Java | .java |
tree-sitter |
| C# | .cs |
tree-sitter |
| Dart | .dart |
tree-sitter |
| Kotlin | .kt, .kts |
tree-sitter |
| Swift | .swift |
tree-sitter |
| Ruby | .rb |
tree-sitter |
| Solidity | .sol |
tree-sitter |
| HCL / Terraform | .tf, .hcl |
tree-sitter |
| Dockerfile | Dockerfile, Dockerfile.* |
line-based |
| Protobuf | .proto |
line-based |
| SQL | .sql |
line-based |
| YAML | .yml, .yaml |
line-based |
Security & Privacy
vfs is local-only and offline.
| Property | Detail |
|---|---|
| Zero network access | All parsing is local. No outbound connections, ever |
| No secrets exposure | Does not read or store API keys, credentials, or environment variables |
| No data collection | No telemetry, no analytics, no tracking |
| No code storage | Source is parsed in memory and discarded. Only ~/.vfs/history.jsonl (scan statistics) is written |
Configuration
There is no config file -- vfs is zero-config. The only state it keeps is scan history for stats and the dashboard:
| File | Purpose |
|---|---|
~/.vfs/history.jsonl |
One line per invocation (paths, filter, bytes, tokens saved) |
~/.vfs/vfs.state |
Running server PID + endpoints (used by up/down/status) |
Clear it anytime with vfs stats --reset.
Contributing
Contributions welcome! See CONTRIBUTING.md for guidelines. When you add a language, update the supported-languages tables in AGENTS.md and README.md.
Releases are automated via .github/workflows/release.yml -- see scripts/release.sh.
Used By
Using vfs in your project or company? Submit a PR to be listed here.
| Logo | Name | Website | Use Case | Blog |
|---|---|---|---|---|
| (img url) | (Company/Project Name) | Website | (Use Case Description) | Read |
How to Add Your Use Case
- Fork this repo and create a branch:
usecase/<your-company-or-project> - Add one row to the table above (logo, name, website, one-line use case, optional blog).
- Open a pull request titled
usecase: add <Company/Project>.
No proprietary details needed -- a high-level description is fine.
License
MIT
