
speedread
io.github.brennengreen由 GitHub 帳號 brennengreen 發布v0.1.0更新於 Oct 24, 2026
Token-efficient code reading for coding agents: symbol-aware, budgeted, diff-aware reads.
概覽
本機 MCP 伺服器兼命令列工具,為程式編寫代理提供依 token 預算、符號感知的程式碼搜尋、結構概覽、呼叫追蹤與增量讀取。
- 可以做什麼
- 產生儲存庫結構概覽,含行數,可選擇列出頂層符號
- 搜尋程式碼,命中結果依所屬函式或類別分組
- 追蹤呼叫端、被呼叫端、參照與實作,最多三層深度
- 在一次批次、受預算限制的呼叫中讀取檔案、行區間、符號、Markdown 章節與設定鍵
- 依 etag 重讀檔案,只回傳依符號標註的變更部分
- 適用情境
- 當代理為了回答程式碼問題或追蹤呼叫鏈而反覆開啟檔案、執行 grep,產生大量往返時適用,可在 token 預算內取得更少但更密集的讀取結果。它應被設定為代理的主要讀取工具,而不是與內建檔案工具並列加入。
- 執行需求
- 以本機 stdio 程序執行(speedread mcp),支援 macOS 與 Linux,不支援 Windows。可從原始碼安裝(需 Rust 1.90+ 與 C 編譯器)、透過 Homebrew 安裝,或使用 macOS Apple Silicon 預編譯二進位檔及 Claude Desktop 安裝包。工作區根目錄來自 --root、CLAUDE_PROJECT_DIR、用戶端的 MCP roots 或目前目錄。選用環境變數 SPEEDREAD_TOKENIZER、SPEEDREAD_THREADS、SPEEDREAD_WALKER 可調整行為。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 speedread,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
[speedread: token-efficient code navigation for AI agents]
[CI] [MIT] [macOS · Apple Silicon] [MCP server + CLI] [Rust]
speedread
Token-efficient code search and navigation for AI coding agents. speedread is an MCP server and CLI that gives Claude Code, GitHub Copilot, Codex, Cursor, Gemini CLI and other agents the part of a codebase a question needs, within a token budget: the function around each search hit, a large file's skeleton, a symbol's callers and implementations, or only what changed since the last read. Not whole files and bare grep hits.
Read is the wrong abstraction for coding agents. Agent code reading should be adaptive, stateful, symbol-aware and token-budgeted instead of byte-oriented. Every model call re-sends the system prompt, tool definitions and conversation so far (18–21k tokens before any code, in our evals), so an agent's cost is driven more by round trips than by bytes. ripgrep returns matches and cat returns bytes, so the agent asks again: open the file, find the function, search for the next hop. speedread returns the minimum useful unit of code for the question, with enough structure that the next call often isn't needed.
One of the ten code-question tasks, replayed from its recorded eval transcripts at recorded speed; all three trials of each condition behaved identically. The built-in grep answers with a file name, so the agent has to ask again, twice. speedread's search answers with the matching lines under their enclosing declaration. This is the second-largest saving of the ten tasks; two tasks came out about 1% worse, and across all ten, input tokens fell 35%. Full interactive report: brennengreen.github.io/speedread (also self-contained in demo/index.html), generated by demo/build.py from evals/results/.
Measured, not hand-waved
Real agents on real repositories, with the same model (claude-sonnet-5) and harness (GitHub Copilot CLI) in both arms: built-in tools vs speedread as the reader. Every trial, transcript, grader and diff is committed, including the workloads where speedread didn't help.
- Round trips drive the savings. speedread saves where it removes model calls: answers with enclosing context, batched reads,
tracein one hop. On bug fixes, editing and testing dominate the turns, and read results were about 1% of input, so tokens barely moved. - Adoption decides everything. An unused MCP server is not free: its tool definitions ride along on every call (+2.2k tokens per call, measured). Configure it as the reader.
- Scope. One model in one harness, and the relationship and bug-fix suites are small. Other clients and models are untested; treat these numbers as evidence for this setup, not a promise for yours.
pass^3 is the share of tasks whose three trials all passed. Intervals are 95% bootstrap intervals on the ratio of means (evals/stats.py). Per-suite detail: Results · method: evals/README.md · every table: evals/RESULTS.md · raw trials and transcripts: evals/results/
Quick start
1. Install (macOS on Apple Silicon, Rust 1.90+; a clean build took 80 s on an M4, plus downloads):
Prebuilt binaries, a one-click Claude Desktop bundle, other platforms, and why the tap name: Install.
2. Add it to your agent as the reader, not as one more tool. Installed alongside the built-in tools with no guidance, it went unused and made runs more expensive (above).
VS Code, Cursor, Codex, Gemini CLI, Zed and Claude Desktop: Configuration. Where the built-in tools can't be removed, add the reading instructions to AGENTS.md, CLAUDE.md or .github/copilot-instructions.md.
3. Or try it by hand in any repository:
The primitives
Four tools over MCP, mirrored by the CLI:
read: batched, budgeted, symbol-aware
One call takes any mix of targets. They share one token budget (default 8,000).
A real skeleton of flask's 1,628-line app.py (excerpt) costs 3.4k tokens, against 21k for the file:
Symbol-aware re-reads. After an edit, path@etag returns unchanged, the appended tail for a growing log, or a diff that names what changed. Hunks carry git-style function context, and mode=outline returns only the symbol summary. From tests/mcp.rs:
A signature edit reads f3 [25-27]: signature changed: `pub fn f3() -> u32` → `pub fn f3(k: u32) -> u32` ; a new function reads g [133-135]: added `pub fn g() -> u8` .
Etags are 64-bit. An etag is the full 64-bit xxh3 of the content, printed as 16 hex digits, and snapshots of what the agent has seen live in a 256 MB LRU keyed by it. Two different contents would have to collide in 64 bits to alias. Across 100,000 snapshots in one session that chance is about 3 × 10⁻¹⁰. Identical contents share an etag, which is correct. Shorter tags are rejected rather than prefix-matched.
search: hits grouped by enclosing symbol
output=symbols returns the full source of every enclosing function in the same call. output=files returns paths with counts.
trace: relationships, not text
The expensive agent loop is search → open → search again to follow a call chain. trace does it in one call. Real output on gin (abridged):
Its four directions:
callers: call sites grouped by calling function;depth2–3 builds the tree.callees: each call in the body, resolved to its definition.refs: every use, including imports and type mentions.impls: subclasses and trait, protocol and interface implementations. Go interfaces are matched structurally, by method sets. A method target lists each override.
Comments and strings are excluded by tree-sitter. Same-named definitions are told apart by receiver, enclosing class, Go package and file. Sites that stay ambiguous are marked ?, never silently merged. It is syntactic, with no type inference. See Limitations.
map: a budgeted overview
A .gitignore-aware tree with line counts. Directories expand by importance until the budget (default 3,000) is spent: source first, then hidden, test or vendored trees. symbols=true adds each file's top-level definitions. Symlinks are listed as name → target and never followed.
Code execution and Skills
Anthropic's Code execution with MCP argues for filtering data before it reaches the model. The four tool definitions cost ~1.4k tokens in total. The CLI mirrors them and adds JSON Lines for agents that script:
skills/speedread/SKILL.md packages the workflow as an Agent Skill.
Results
Every number here comes from an eval in evals/, built to Anthropic's Demystifying evals for AI agents: explicit tasks, repeated trials, deterministic outcome graders, pass@k and pass^k, balanced task sets with controls, isolated trials and transcripts read. Raw data, every transcript included, is committed. All agent trials use claude-sonnet-5 via GitHub Copilot CLI, with exact token counts from the harness's usage log. The summary table covers all four real-agent workloads, not just the best one.
Code questions
Suite 3: 10 questions with version-specific answers, over 6 repositories and 5 languages, with 3 trials each. Cost fell on 10 of 10 tasks, and tool results were about the same size in both conditions: the saving is two fewer round trips per answer. As the reader, speedread was used in 27 of 30 trials; the 3 exceptions were a 41-line go.mod, which the agent read with cat. This suite ran before trace, symbol diffs and the content-aware estimator existed.
Relationship questions
[Relationship questions: −57% input tokens overall; multi-hop callers −73%, resolved callees −59%]
Suite 3b asks for two-hop callers, resolved callees, Go interface implementations (structural) and Rust trait implementations. Two of the four are answerable with one good grep; they are the controls. Unprompted, the agent chose trace in 7 of 8 trials. On the two-hop question, built-in tools took 7–14 tool calls and 186k–277k tokens. With speedread, the agent called trace with depth: 2, checked one more function and answered: 2 calls, 61k tokens. The sample is small (8 trials per arm), so treat the size of the effect as approximate.
Transcript review changed this suite's grader. Both baseline trials of the two-hop task excluded BasicAuth, arguing that its AbortWithStatus call sits inside the closure BasicAuthForRealm returns, which the router invokes as a value. That is a defensible reading, so the grader now accepts both answers. trace attributes calls inside closures to the enclosing named function; this is listed under limitations.
Bug fixes (SWE-style)
Suite 4 injects 8 real regressions into gin (Go) and flask (Python), gives the agent a symptom-only bug report and grades by the repository's full test suite, with tests unmodified. Every task is verified to fail as injected and to pass with the reference fix. The four conditions are:
- baseline: built-in tools only
- available: speedread installed, no guidance
- preferred: one sentence asking the agent to use it for reading
- exclusive: built-in view/grep/glob removed; edit and bash stay
That is 64 trials:
- No quality cost. 64 of 64 trials passed. Compression never hid the bug: in 0 of the 32 trials that used speedread was the file with the bug first shown as a skeleton or outline before the buggy line itself. Agents searched first and then read exact ranges.
- Adoption is binary. Available was chosen in 0 of 16 trials, yet it used more input tokens than baseline on 8 of 8 tasks (+46%; cost +30%). One sentence of guidance took adoption to 16 of 16, with 78% of reads done through speedread.
- Fewer turns and less time; tokens flat. Preferred took fewer model calls on 7 of 8 tasks (median 5 instead of 6) and 24% less model time. Exclusive took 27% less model time, lower on 7 of 8 tasks. Cost fell 4–6%, but input tokens stayed within noise (−3%, −1%). With 16 trials per arm none of these intervals exclude zero, so read them as directions (stats).
- Not observed: the "same success at 50–90% less context" a reviewer hoped for. It holds where reading dominates the turns, and not on short edit-and-test loops.
tracewas never called in these 32 trials: fixing a bug from its symptom needed search and read, not a call graph.
Tool level
[Tool-level scenarios: 954,734 → 67,079 tokens (−93%) across 35 graded scenarios]
Suite 1 covers 35 reading scenarios on real repositories. Each is graded for information sufficiency: a smaller answer that drops what the task needs fails. It shows what the primitives compress, and several comparisons are structurally favorable: whole-file reads and 2,000-line paging. The fair comparison is the best-case baseline, which greps for the name and reads exactly the function: −46%, in one call instead of two. The real-agent suites above are the evidence for agent performance.
The budget contract
[Reads over budget on hostile content: 9.5% → 0% (525 reads)]
Budgets are in tokens, but no client tells a server its tokenizer. Suite 2 attacks the estimator with SVG path data, JSON, lockfiles, minified JS, real CJK docs, emoji, base64, hex dumps and numeric tables. Under o200k, cl100k and the legacy Claude tokenizer, a fixed 2.6 bytes/token put 9.5% of reads over budget, the worst at 1.81×. The content-aware estimator (src/tokens.rs) models tokens from character classes and is fitted to the stricter of o200k and legacy Claude. It puts 0 of 525 reads over budget (worst 0.99×).
Calibrated against a production tokenizer. Offline tokenizers are proxies. The harness logs exact input tokens per model call, so the real cost of each tool result can be recovered from consecutive calls (Suite 2b). On claude-sonnet-5, real counts run 1.22× the estimate at the median, and 1.36× for speedread's own output, which matches Anthropic's note that Claude 4.7+ tokenizers produce ~30% more tokens. Clients that identify as Claude therefore get a Claude profile that scales budgets 1.4×. Force it anywhere with SPEEDREAD_TOKENIZER=claude; openai and legacy are the other profiles.
Speed
Speed is not the headline; returning less is. It still matters that doing more work per call, like parsing, grouping and budgeting, doesn't cost latency. Measured on an Apple M4 (4P + 6E cores), warm cache, medians:
Search runs at parity with ripgrep when ripgrep is told to use only the performance cores. The 2.9× gap to ripgrep's default comes from threads spilling onto efficiency cores on this chip: kernel time grows 6.6×. speedread sizes its pool from hw.perflevel0.logicalcpu.
How it compares
Other MCP servers cover parts of this. The official filesystem server batches whole-file reads and limits them by line count. Serena is symbol-aware through language servers. ast-grep MCP does structural search, claude-context searches by embeddings, and repomix packs a whole repository into one file. speedread combines batched, symbol-aware reads under one token budget with diff-only re-reads and relationship queries, and needs no embeddings or language server. The feature table, with sources, is in docs/RESEARCH.md.
Install
From source (Rust 1.90+, via brew install rust or rustup; the tree-sitter grammars also need a C compiler, which Xcode's Command Line Tools provide):
This installs one native binary, ~/.cargo/bin/speedread, with no runtime dependencies. --locked builds the dependency versions in Cargo.lock, which CI tests.
Prebuilt, macOS on Apple Silicon: each release attaches the binary and its SHA-256.
The binary is not notarized. curl doesn't set macOS's quarantine flag; if you download it with a browser instead, clear it with xattr -d com.apple.quarantine speedread.
Claude Desktop, one click: download speedread-aarch64-apple-darwin.mcpb and open it. Claude Desktop asks which folder speedread may read; reads outside it are refused.
Homebrew: brew install brennengreen/tap/speedread builds from source. Use the full name: plain brew install speedread installs a different program, an RSVP speed-reading tool from homebrew-core that also installs a speedread binary.
MCP Registry: listed as io.github.brennengreen/speedread (mcp-name: io.github.brennengreen/speedread), so registry-aware clients can find and install the bundle. Agents installing speedread for you can follow llms-install.md.
New versions are published as releases with notes; to be notified, use Watch → Custom → Releases.
Platform support
The speed figures in Results are from an Apple M4.
Make it the reader
Availability is not adoption. Installed next to the built-in tools with no guidance, speedread was used in 0 of 26 trials across two suites. Those runs also cost more than not installing it (+31% and +46% input tokens), because its tool definitions ride along on every model call. One sentence of guidance took adoption to 16 of 16. So configure speedread as the reader, not as one option among many.
GitHub Copilot CLI: add the server, then remove the built-in readers. Edit and bash stay.
Claude Code:
Claude Code caveat, quantified. Claude Code's
Edit/Writerequire a prior nativeReadof the file; MCP reads don't count (claude-code#32214, closed as not planned). speedread can't remove that read. In the bug-fix suite, speedread's agents edited files they had only seen through speedread. A full defaultReadof each costs 2k–21k tokens (median 9.8k) and is then re-sent on every later turn. Adding it (an upper bound) moves preferred from −3% to +10% input tokens against baseline, and exclusive from −1% to +19%. The baseline doesn't change, because it read those files natively anyway. A rangedReadof the edit site is probably enough to satisfy the check, but that's unverified. In Claude Code, expect speedread to save turns and time on edit-heavy work, not tokens; the exploration and relationship savings above still apply.
VS Code, Cursor, Codex, Gemini CLI, Zed, Claude Desktop: see configuration. Add this to AGENTS.md, CLAUDE.md or .github/copilot-instructions.md:
Configuration
speedread serves MCP over stdio (speedread mcp). Workspace roots come from --root <dir> (repeatable), then $CLAUDE_PROJECT_DIR, then the client's MCP roots (VS Code/Cursor folders, Claude Code --add-dir), then the current directory. Usually no flags are needed.
GUI apps may not inherit your shell's PATH; use the absolute path from which speedread.
Environment variables:
SPEEDREAD_TOKENIZER=claude|openai|legacypins the budget calibration (default: detect from the client, elselegacy).SPEEDREAD_THREADSsets the worker count (default: performance cores).SPEEDREAD_WALKER=portableuses the portable walker.
Limitations and roadmap
traceis syntactic. It uses tree-sitter plus name resolution by receiver, class and package, with no type inference, sox.f()on an unknown receiver matches everyf, marked?. Calls inside closures and lambdas are attributed to the enclosing named function, and functions passed as values aren't calls. The next step is an optional LSP/SCIP layer behind the sametraceinterface, for exact references, overrides and call hierarchies.- Definition overhead and adoption. The server adds ~2.2k tokens to every model call (net +0.9k when it replaces view/grep/glob), whether or not it's used. Leaner descriptions, A/B tests of tool names and descriptions for unprompted adoption, and a single high-level
contexttool that picks map, search, trace or read itself are next. - Sample sizes. The bug-fix and relationship suites have 16 and 8 trials per arm, and their bug-fix token and time differences are within noise. More tasks, more trials and other harnesses (Claude Code, Codex) are next.
- Budgets are estimates, not tokenizer counts. They are calibrated to offline tokenizers, plus the Claude profile from production counts.
- Built and tuned for macOS on Apple Silicon. Linux passes the test suite in CI but isn't tuned; Intel macOS isn't in CI. Windows is not supported. See Platform support.
Each of these is written up with its scope, the skills it needs and a suggested first step in ROADMAP.md.
Security
Read-only by construction: there are no write tools. Paths are canonicalized and must lie inside a root. Dependency caches (~/.cargo/registry, ~/go/pkg/mod, SwiftPM checkouts, SDKs) are readable; --no-deps turns that off and --unrestricted lifts all path limits. macOS privacy protections still apply. Report vulnerabilities privately; see SECURITY.md.
How it works
- Budget ladder. Each target has four views: full, skeleton, compact skeleton (comment, docstring and import runs folded) and outline. Items degrade largest-first until the batch fits: exploratory targets before requested symbols, and explicit ranges never. A final outline keeps every top-level symbol and fills in members breadth-first. Responses are sized with the content-aware estimate, then checked once more before they're sent. The maximum budget (10k) keeps results inline in every client: Copilot CLI spills results over 30 KB to a file, and Claude Code warns above 10k tokens.
- Outlines. tree-sitter covers Rust, Python, JavaScript, TypeScript/TSX, Go, Java, C, C++, C#, Ruby, PHP, Bash, Swift, Kotlin, Scala, Lua, Luau (
.luau, and.luafiles that use Luau syntax) and Objective-C. Single-pass scanners handle Markdown, JSON, YAML and TOML. Apple SDK macros are blanked before parsing Objective-C and C headers; otherwise tree-sitter's error recovery drops the rest of the file. Luau attributes such as@native, which the grammar predates, are blanked the same way. - Caches. Sources are validated by (size, mtime ns, inode, device) on every access. Outlines are cached by content hash, and the long-lived MCP process keeps both warm.
- macOS.
- A
getattrlistbulk(2)walker gets name, type, size, mtime and flags for a batch of entries in one syscall: 1.8× faster than readdir+lstat. - Worker pools are sized to the performance cores, at
QOS_CLASS_USER_INITIATED. - iCloud dataless files fail fast instead of downloading (
IOPOL_TYPE_VFS_MATERIALIZE_DATALESS_FILES). - The 256-descriptor soft limit that launchd gives GUI-spawned processes is raised.
- No mmap for cached files: SIGBUS when editors truncate in place.
- NEON
memchr,simdutf8,xxh3andmimalloc.
- A
The research behind every design choice, with sources, is in docs/RESEARCH.md.
Contributing
Issues, eval results and pull requests are welcome, including results where speedread doesn't help. Setup questions and ideas go in Discussions. Useful places to start:
- Linux: the tests pass in CI; real-world reports are welcome. A small first fix: five macOS-only helpers make clippy fail there.
- Other harnesses and models: Claude Code, Codex, Cursor and Gemini CLI are configured above but not yet measured. Share an eval result.
- Languages and clients: an outline fixture for a language that parses poorly, or a verified setup for a client.
CONTRIBUTING.md covers setup, tests, adding a language and one rule specific to this project: tool descriptions and server instructions are read by the model, so changing them can change adoption, and they need an eval. ROADMAP.md lists scoped work, including which items suit a first contribution.
Development
License
MIT © 2026 Brennen Green
來源:README.md,提交 37abea2
工具
0版本歷史
1- v0.1.0最新Sep 27, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分