Local-first codebase context engine for AI coding agents
Rust
0
190 commits
updated May 7, 2026
Local-first codebase context engine for AI coding agents.
codesurgeon parses your codebase into a symbol dependency graph, then serves token-budgeted context capsules to Claude (or any MCP-compatible agent) via the Model Context Protocol. Only the code that matters for your task is returned — full source for the most relevant symbols, signatures-only for adjacent ones.
| Metric | Baseline (full context) | codesurgeon |
|---|---|---|
| Tokens per query (30-file project) | ~30,000 | ~3,000 |
| Token reduction | — | ~90% |
| Relevant pivots surfaced | all files | 8 symbols |
| Setup | none | cargo install + 1 config line |
Token figures are from the leading competitor's published results. codesurgeon reports your actual per-workspace savings via
codesurgeon stats(or theget_statsMCP tool).
The leading competitor in this space benchmarked against SWE-bench Verified — 100 real GitHub issues, same model and cost cap across all agents:
| Agent | Pass@1 | $/Task |
|---|---|---|
| Leading competitor + Claude Code | 73% | $0.67 |
| OpenHands | 70% | $1.77 |
| Sonar Foundation | 70% | $1.98 |
Key insight from the per-repo breakdown: dependency-graph context (like codesurgeon's symbol graph) yields large gains on import-heavy, interconnected codebases (astropy: 80% vs 40% for alternatives) but smaller gains on rendering-heavy or procedural code (matplotlib: 43% vs 86%). codesurgeon is best suited for Rust, Python backend, and TypeScript projects with deep module graphs.
codesurgeon will run the same benchmark once Phase 8 (tool parity) and Phase 9 (session memory) are stable.
Compared to the leading alternative:
| Leading alternative | codesurgeon | |
|---|---|---|
| Runtime | TypeScript/Node.js wrapper + Rust core | Pure Rust, single binary |
| Search | FTS5 + TF-IDF | BM25 (Tantivy) + graph centrality + optional embeddings |
| Embeddings | None | nomic-embed-text-v1.5 (768-dim, Apple Silicon Metal) |
| Call edges | caller → callee | caller → callee + args snippet |
| Graph extras | imports, calls | + trait impls, type-flow references |
| Diff support | No | get_diff_capsule for PR review |
| Session memory | No | Cross-session observations, stale detection |
| Languages | Python, JS/TS, Rust | + Swift, Shell, HTML, SQL |
Your codebase
│
▼
tree-sitter AST parsing (parallel, rayon)
│
▼
Symbol graph (petgraph DAG)
Nodes: functions, classes, structs, enums, methods
Edges: Calls, Imports, Implements, Inherits, References
│
▼
Query: "fix the retry logic in the HTTP client"
│
├─ Intent detection → Debug
├─ BM25 search (Tantivy) → top-50 candidates
├─ Graph centrality boost → re-rank
├─ Semantic similarity blend (embeddings, optional)
└─ Token-budgeted capsule assembly
├─ Pivots (8): full source of most relevant symbols
└─ Adjacents (20): signatures only (70–90% smaller)
Grab the latest release for your platform from the Releases page:
# Apple Silicon
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-aarch64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/
# Intel Mac
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/
# Linux x86_64
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/
git clone https://github.com/subsriram/codesurgeon
cd codesurgeon
# Apple Silicon (Metal embeddings, recommended)
cargo build --release --features metal
# CPU-only embeddings
cargo build --release --features embeddings
# No embeddings (BM25 + graph only)
cargo build --release
This produces two binaries in target/release/:
codesurgeon — the CLIcodesurgeon-mcp — the MCP server (add to Claude Code / Codex)To use the codesurgeon CLI from anywhere, either symlink them onto your PATH or add target/release to your shell's PATH:
sudo ln -sf "$(pwd)/target/release/codesurgeon" /usr/local/bin/codesurgeon
sudo ln -sf "$(pwd)/target/release/codesurgeon-mcp" /usr/local/bin/codesurgeon-mcp
claude mcp add --scope user \
-e CS_WORKSPACE=/path/to/your/project \
cs-myproject \
/path/to/codesurgeon/target/release/codesurgeon-mcp
This writes to ~/.claude.json (CLI v2.x). Restart Claude Code — the server indexes your workspace in the background on first start.
Run claude mcp add once per project with a unique server name:
claude mcp add --scope user \
-e CS_WORKSPACE=/projects/frontend \
cs-frontend \
/path/to/codesurgeon-mcp
claude mcp add --scope user \
-e CS_WORKSPACE=/projects/backend \
cs-backend \
/path/to/codesurgeon-mcp
Tools are namespaced: cs-frontend__run_pipeline, cs-backend__run_pipeline, etc.
Before editing: run_pipeline(task="add retry logic to the HTTP client")
Before refactoring: get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")
Navigating code: get_skeleton(file_path="src/http.rs")
After solving hard problem: save_observation(content="retry uses exponential backoff")
| Tool | When to use |
|---|---|
run_pipeline | Before every edit — primary tool |
get_context_capsule | Lightweight search for a specific query |
get_impact_graph | Before any refactor — see what breaks |
get_skeleton | Understand a file's shape without reading bodies |
search_logic_flow | Trace how A calls B |
get_diff_capsule | Context for a PR or patch |
index_status | Health check / Xcode MCP availability |
get_session_context | Catch up at the start of a session |
save_observation | Persist an insight across sessions |
generate_module_docs | Write per-directory CLAUDE.md files |
run_pipeline — your primary tool
Call this before every edit. Give it a plain-English task description. It auto-detects intent (debug / refactor / add / explore / structural), runs BM25 + graph centrality + semantic search, and returns a token-budgeted capsule: full source for the 8 most relevant symbols, signatures-only for up to 20 adjacent ones, plus anything remembered from previous sessions.
run_pipeline(task="fix the retry logic in the HTTP client")
Optional context parameter — pass the raw verbatim source the task was derived from (full problem statement, bug report, error trace). Identifiers present in the raw source but paraphrased out of task are recovered via anchor extraction, which runs on task + context while BM25/semantic/intent detection stay on task alone.
run_pipeline(
task="fix PolynomialError on subs with Piecewise",
context="<full GitHub issue body with code snippet and traceback>"
)
get_context_capsule — lightweight search
Same search engine as run_pipeline but without intent routing or session memory. Use it when you have a specific query and don't need the full pipeline.
get_context_capsule(query="token budget assembly")
get_impact_graph — blast radius before a refactor
Call this before renaming or changing any function or type. Give it a fully-qualified symbol name and it returns all direct and transitive callers — everything that will break.
get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")
get_skeleton — file API surface
Returns all signatures and docstrings from a file with bodies stripped out. Typically 70–90% fewer tokens than the full file. Use it when you need to understand what a file exports without reading everything.
get_skeleton(file_path="src/engine.rs")
search_logic_flow — trace a path between two functions
Finds the shortest call-graph path from one symbol to another. Use it to understand how A eventually reaches B, or to debug unexpected call chains.
search_logic_flow(from_fqn="src/main.rs::handle_request", to_fqn="src/db.rs::query")
get_diff_capsule — context for a PR or patch
Paste in a git diff and it returns the changed symbols, their callers, and related test files — all token-budgeted. Designed for code review.
get_diff_capsule(diff="<paste unified diff here>")
index_status — health check
Returns symbol count, edge count, file count, session ID, and Xcode MCP availability. Call it to confirm the index is ready after startup, or to check whether re-indexing is still in progress.
index_status()
get_session_context — what was learned before
Returns the last ~50 observations saved across all sessions for this workspace. Use it at the start of a session to catch up on what was discovered previously.
get_session_context()
save_observation — persist an insight
Saves a note tied optionally to a specific symbol. Persists across sessions and is surfaced by run_pipeline in future sessions. Call it after solving something non-obvious.
save_observation(content="retry uses exponential backoff, max 3 attempts", symbol_fqn="src/http.rs::HttpClient::send")
generate_module_docs — write CLAUDE.md files per directory
Generates per-directory CLAUDE.md summaries from the symbol graph — types, functions, and (for Swift directories) Xcode MCP guidance. Pass write_files=true to write them to disk.
generate_module_docs(write_files=true)
| Situation | Tool |
|---|---|
| About to edit anything | run_pipeline |
| About to rename / move / delete | get_impact_graph first |
| Unfamiliar file, need the shape | get_skeleton |
| Reviewing a PR | get_diff_capsule |
| How does A call B? | search_logic_flow |
| Is the index ready? | index_status |
| Starting a new session | get_session_context |
| Just solved something tricky | save_observation |
| Setting up a new project | generate_module_docs |
codesurgeon index # Index (or re-index) workspace
codesurgeon status # Symbol/edge/file counts
codesurgeon search "retry logic" # BM25 search
codesurgeon skeleton src/http.rs # File skeleton
codesurgeon impact src/http.rs::send # Blast radius
codesurgeon flow src/http.rs::send src/retry.rs::with_retry # Logic flow
codesurgeon diff - < my.patch # Diff-aware capsule (stdin)
git diff | codesurgeon diff - # Pipe from git diff
codesurgeon diff "$(git diff)" # Inline diff text
codesurgeon context "fix auth bug" # Full run_pipeline from CLI
codesurgeon config # Show current configuration
codesurgeon docs # Generate per-module CLAUDE.md files
codesurgeon memory # List saved observations (shows IDs)
codesurgeon memory --delete <id> # Delete an observation by ID
codesurgeon observe "insight text" # Save a manual observation
codesurgeon observe "insight" --symbol src/http.rs::send # Attach to a symbol
codesurgeon submit-lsp-edges edges.json # Push LSP-resolved type edges from a file
cat edges.json | codesurgeon submit-lsp-edges # …or from stdin
| Language | Parser | Notes |
|---|---|---|
| Rust | tree-sitter | Full AST incl. impl/trait |
| Python | tree-sitter | Full AST |
| TypeScript / TSX | tree-sitter | Full AST; optional resolved types via TS compiler shim |
| JavaScript / JSX | tree-sitter | Full AST; optional resolved types via TS compiler shim |
| Swift | tree-sitter + Xcode MCP (optional) | Full AST — class/struct/enum/extension/protocol/func/method; Xcode MCP adds resolved types |
| Shell (bash/zsh) | tree-sitter | Function extraction |
| HTML | tree-sitter | Script/style blocks |
| SQL | tree-sitter | CREATE TABLE/VIEW/FUNCTION/INDEX/TYPE |
codesurgeon's tree-sitter pass gives you full TypeScript/JavaScript symbol structure. For resolved types (e.g. Promise<User> instead of Promise<any>), enable the optional compiler shim:
Requirements: node on PATH, tsconfig.json in your workspace root, and typescript in node_modules (or globally installed).
Enable by adding to .codesurgeon/config.toml:
[indexing]
ts_types = true
At index time codesurgeon invokes a bundled Node.js script (ts-enricher.js) that runs ts.createProgram() + TypeChecker over your workspace and annotates symbols with their resolved return/property types. The results are stored in the index as resolved_type and surfaced in context capsules.
Incremental: the shim only re-runs when tsconfig.json changes. Existing annotations are preserved across re-indexes.
Plain JS: the shim sets allowJs: true, so JSDoc-annotated JavaScript files are resolved correctly too.
VS Code users: if you have the codesurgeon VS Code extension installed, the submit_lsp_edges tool pushed from the running TypeScript language server is the faster alternative — no subprocess spawning required. ts_types is the right choice for CI, Codex, or non-VS Code editors.
codesurgeon's tree-sitter pass gives you full Swift symbol structure. For resolved types and live build diagnostics, pair it with Xcode MCP (Xcode 26+):
# Enable in Xcode: Settings → Intelligence → Enable Model Context Protocol
xcrun mcpbridge install --claude-code
When Xcode MCP is configured, run_pipeline on Swift files will note its availability
and agents can call its tools for type-resolved details. When it's absent, run_pipeline
says so explicitly — the tree-sitter graph remains fully usable for semantic search,
impact analysis, and session memory. index_status always reports whether Xcode MCP
was detected.
For Xcode < 26 or SPM-only projects: XcodeBuildMCP or xcode-mcp-server.
codesurgeon is fully local-first. Your code never leaves your machine.
.codesurgeon/index.db alongside your project (gitignored by default)The only binary that runs is codesurgeon-mcp, started by your MCP client (Claude Code / Codex) as a subprocess over stdio. It reads your source files, builds a local index, and responds to tool calls — nothing else.
Symptom: Tools like run_pipeline are not available, or Claude reports the MCP server failed to start.
CS_WORKSPACE points to an existing directory:
echo $CS_WORKSPACE
ls "$CS_WORKSPACE"
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' \
| CS_WORKSPACE=/path/to/project timeout 5 ./target/release/codesurgeon-mcp
A healthy server replies with an initialize response on stdout. Any error on stderr explains the failure.~/.claude.json (Claude Code CLI v2.x):
claude mcp list
Symptom: index_status() returns 0 symbols, or results look stale after editing files.
index_status() again to confirm.CS_WORKSPACE=/path/to/project codesurgeon index
CS_WORKSPACE=/path/to/project codesurgeon status
Symptom: A second Claude Code window or parallel Codex probe connects but sees no results, or logs show "serving read-only".
This is expected behaviour. Only one codesurgeon-mcp instance per workspace runs background indexing (the first one to acquire the PID lock). Subsequent instances serve the existing index read-only — they won't write new embeddings or trigger re-indexing. This is intentional to avoid concurrent index writes.
If you want the new instance to become the primary, stop the existing one first:
kill $(cat /path/to/project/.codesurgeon/mcp.pid)
Symptom: After a hard kill or power loss, new instances unexpectedly enter read-only mode.
codesurgeon auto-detects this: on startup it reads the existing PID file and runs kill -0 <pid> to check whether that process is actually alive. If it's dead, the stale file is overwritten automatically and the new instance becomes primary. No manual cleanup is needed in normal cases.
If for some reason this fails (e.g. the PID was reused by a system process), delete the file manually:
rm /path/to/project/.codesurgeon/mcp.pid
cargo buildSymptom: codesurgeon or codesurgeon-mcp command not found.
The binaries are placed in target/release/, not on your PATH automatically. Either use the full path:
/path/to/codesurgeon/target/release/codesurgeon-mcp
Or add the release directory to your PATH, or symlink:
ln -s /path/to/codesurgeon/target/release/codesurgeon /usr/local/bin/codesurgeon
Set CS_LOG (a tracing-subscriber env-filter
expression) to see detailed output from the MCP server or CLI. Default: warn.
# Info-level (recommended for troubleshooting)
CS_LOG=info CS_WORKSPACE=/path/to/project codesurgeon query "my search"
# Debug-level (verbose — shows every file indexed, every query scored)
CS_LOG=debug CS_WORKSPACE=/path/to/project ./target/release/codesurgeon-mcp
# Trace a specific module
CS_LOG=cs_core::engine=debug codesurgeon query "my search"
codesurgeon is configured via .codesurgeon/config.toml in your project root.
A user-level fallback at ~/.config/codesurgeon/config.toml is also loaded
(workspace settings take precedence). All settings are optional — sensible
defaults apply when files are missing.
[context]
# Token budget per context capsule (default: 4000)
max_tokens = 4000
# How much body text to include for adjacent (skeleton) symbols:
# "minimal" — ~5% of body (signatures only, very tight)
# "standard" — ~15% of body (default)
# "detailed" — ~30% of body (for large-context models like claude-opus)
skeleton_detail = "standard"
[indexing]
# Enable TypeScript compiler enrichment (requires node + typescript in node_modules)
ts_types = false
# Enable Pyright type enrichment (requires pyright on PATH)
python_pyright = false
# Enable cargo-expand macro enrichment (requires cargo-expand)
rust_expand_macros = false
# Enable rustdoc JSON type enrichment (requires nightly Rust)
rust_rustdoc_types = false
[memory]
# Auto-observations expire after this many days (default: 7)
auto_ttl_days = 7
# Manual observations never expire by default; set to override
# manual_ttl_days = 90
[git]
# Write manifest.json for git-tracked index metadata
track_manifest = false
[observability]
# USD cost per token for savings display in `codesurgeon stats` (default: 0.000003)
token_rate_usd = 0.000003
Run codesurgeon config to see the effective merged settings and their sources.
Most settings live in config.toml (above). The following env vars control
runtime concerns that don't belong in committed config:
| Var | Read by | Purpose |
|---|---|---|
CS_WORKSPACE | codesurgeon, codesurgeon-mcp | Workspace root for indexing and queries. Required when not running from inside the workspace. |
CLAUDE_CODE_WORKSPACE | codesurgeon, codesurgeon-mcp | Alias of CS_WORKSPACE, set automatically by Claude Code. CS_WORKSPACE wins if both are set. |
CS_LOG | codesurgeon, codesurgeon-mcp | tracing-subscriber env-filter expression (e.g. info, debug, cs_core::engine=trace). Default: warn. |
CS_TRACK_MANIFEST | codesurgeon, codesurgeon-mcp | Set to 1 to overlay [git] track_manifest = true from the environment, omitting manifest.json from .codesurgeon/.gitignore so it can be shared across clones. |
CS_BENCH_CENTRALITY_K | cargo run --example token_savings | Pin the centrality smoothing constant k for the 20-query bench, e.g. CS_BENCH_CENTRALITY_K=15.0 reproduces pre-#82 behaviour. Unset → corpus-derived (default). Bench-only — has no effect on the binaries. |
Contributions are welcome! Before submitting a PR, run the pre-commit checklist:
cargo fmt --all # Format
cargo clippy --workspace -- -D warnings # Lint (warnings are errors in CI)
cargo test --workspace # Tests
All three must pass. See .github/workflows/ci.yml for the exact CI checks.
MIT — see LICENSE for details.
190 commits
Rust
99.2%
Local-first codebase context engine for AI coding agents
Rust
0
190 commits
updated May 7, 2026
Local-first codebase context engine for AI coding agents.
codesurgeon parses your codebase into a symbol dependency graph, then serves token-budgeted context capsules to Claude (or any MCP-compatible agent) via the Model Context Protocol. Only the code that matters for your task is returned — full source for the most relevant symbols, signatures-only for adjacent ones.
| Metric | Baseline (full context) | codesurgeon |
|---|---|---|
| Tokens per query (30-file project) | ~30,000 | ~3,000 |
| Token reduction | — | ~90% |
| Relevant pivots surfaced | all files | 8 symbols |
| Setup | none | cargo install + 1 config line |
Token figures are from the leading competitor's published results. codesurgeon reports your actual per-workspace savings via
codesurgeon stats(or theget_statsMCP tool).
The leading competitor in this space benchmarked against SWE-bench Verified — 100 real GitHub issues, same model and cost cap across all agents:
| Agent | Pass@1 | $/Task |
|---|---|---|
| Leading competitor + Claude Code | 73% | $0.67 |
| OpenHands | 70% | $1.77 |
| Sonar Foundation | 70% | $1.98 |
Key insight from the per-repo breakdown: dependency-graph context (like codesurgeon's symbol graph) yields large gains on import-heavy, interconnected codebases (astropy: 80% vs 40% for alternatives) but smaller gains on rendering-heavy or procedural code (matplotlib: 43% vs 86%). codesurgeon is best suited for Rust, Python backend, and TypeScript projects with deep module graphs.
codesurgeon will run the same benchmark once Phase 8 (tool parity) and Phase 9 (session memory) are stable.
Compared to the leading alternative:
| Leading alternative | codesurgeon | |
|---|---|---|
| Runtime | TypeScript/Node.js wrapper + Rust core | Pure Rust, single binary |
| Search | FTS5 + TF-IDF | BM25 (Tantivy) + graph centrality + optional embeddings |
| Embeddings | None | nomic-embed-text-v1.5 (768-dim, Apple Silicon Metal) |
| Call edges | caller → callee | caller → callee + args snippet |
| Graph extras | imports, calls | + trait impls, type-flow references |
| Diff support | No | get_diff_capsule for PR review |
| Session memory | No | Cross-session observations, stale detection |
| Languages | Python, JS/TS, Rust | + Swift, Shell, HTML, SQL |
Your codebase
│
▼
tree-sitter AST parsing (parallel, rayon)
│
▼
Symbol graph (petgraph DAG)
Nodes: functions, classes, structs, enums, methods
Edges: Calls, Imports, Implements, Inherits, References
│
▼
Query: "fix the retry logic in the HTTP client"
│
├─ Intent detection → Debug
├─ BM25 search (Tantivy) → top-50 candidates
├─ Graph centrality boost → re-rank
├─ Semantic similarity blend (embeddings, optional)
└─ Token-budgeted capsule assembly
├─ Pivots (8): full source of most relevant symbols
└─ Adjacents (20): signatures only (70–90% smaller)
Grab the latest release for your platform from the Releases page:
# Apple Silicon
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-aarch64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/
# Intel Mac
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/
# Linux x86_64
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/
git clone https://github.com/subsriram/codesurgeon
cd codesurgeon
# Apple Silicon (Metal embeddings, recommended)
cargo build --release --features metal
# CPU-only embeddings
cargo build --release --features embeddings
# No embeddings (BM25 + graph only)
cargo build --release
This produces two binaries in target/release/:
codesurgeon — the CLIcodesurgeon-mcp — the MCP server (add to Claude Code / Codex)To use the codesurgeon CLI from anywhere, either symlink them onto your PATH or add target/release to your shell's PATH:
sudo ln -sf "$(pwd)/target/release/codesurgeon" /usr/local/bin/codesurgeon
sudo ln -sf "$(pwd)/target/release/codesurgeon-mcp" /usr/local/bin/codesurgeon-mcp
claude mcp add --scope user \
-e CS_WORKSPACE=/path/to/your/project \
cs-myproject \
/path/to/codesurgeon/target/release/codesurgeon-mcp
This writes to ~/.claude.json (CLI v2.x). Restart Claude Code — the server indexes your workspace in the background on first start.
Run claude mcp add once per project with a unique server name:
claude mcp add --scope user \
-e CS_WORKSPACE=/projects/frontend \
cs-frontend \
/path/to/codesurgeon-mcp
claude mcp add --scope user \
-e CS_WORKSPACE=/projects/backend \
cs-backend \
/path/to/codesurgeon-mcp
Tools are namespaced: cs-frontend__run_pipeline, cs-backend__run_pipeline, etc.
Before editing: run_pipeline(task="add retry logic to the HTTP client")
Before refactoring: get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")
Navigating code: get_skeleton(file_path="src/http.rs")
After solving hard problem: save_observation(content="retry uses exponential backoff")
| Tool | When to use |
|---|---|
run_pipeline | Before every edit — primary tool |
get_context_capsule | Lightweight search for a specific query |
get_impact_graph | Before any refactor — see what breaks |
get_skeleton | Understand a file's shape without reading bodies |
search_logic_flow | Trace how A calls B |
get_diff_capsule | Context for a PR or patch |
index_status | Health check / Xcode MCP availability |
get_session_context | Catch up at the start of a session |
save_observation | Persist an insight across sessions |
generate_module_docs | Write per-directory CLAUDE.md files |
run_pipeline — your primary tool
Call this before every edit. Give it a plain-English task description. It auto-detects intent (debug / refactor / add / explore / structural), runs BM25 + graph centrality + semantic search, and returns a token-budgeted capsule: full source for the 8 most relevant symbols, signatures-only for up to 20 adjacent ones, plus anything remembered from previous sessions.
run_pipeline(task="fix the retry logic in the HTTP client")
Optional context parameter — pass the raw verbatim source the task was derived from (full problem statement, bug report, error trace). Identifiers present in the raw source but paraphrased out of task are recovered via anchor extraction, which runs on task + context while BM25/semantic/intent detection stay on task alone.
run_pipeline(
task="fix PolynomialError on subs with Piecewise",
context="<full GitHub issue body with code snippet and traceback>"
)
get_context_capsule — lightweight search
Same search engine as run_pipeline but without intent routing or session memory. Use it when you have a specific query and don't need the full pipeline.
get_context_capsule(query="token budget assembly")
get_impact_graph — blast radius before a refactor
Call this before renaming or changing any function or type. Give it a fully-qualified symbol name and it returns all direct and transitive callers — everything that will break.
get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")
get_skeleton — file API surface
Returns all signatures and docstrings from a file with bodies stripped out. Typically 70–90% fewer tokens than the full file. Use it when you need to understand what a file exports without reading everything.
get_skeleton(file_path="src/engine.rs")
search_logic_flow — trace a path between two functions
Finds the shortest call-graph path from one symbol to another. Use it to understand how A eventually reaches B, or to debug unexpected call chains.
search_logic_flow(from_fqn="src/main.rs::handle_request", to_fqn="src/db.rs::query")
get_diff_capsule — context for a PR or patch
Paste in a git diff and it returns the changed symbols, their callers, and related test files — all token-budgeted. Designed for code review.
get_diff_capsule(diff="<paste unified diff here>")
index_status — health check
Returns symbol count, edge count, file count, session ID, and Xcode MCP availability. Call it to confirm the index is ready after startup, or to check whether re-indexing is still in progress.
index_status()
get_session_context — what was learned before
Returns the last ~50 observations saved across all sessions for this workspace. Use it at the start of a session to catch up on what was discovered previously.
get_session_context()
save_observation — persist an insight
Saves a note tied optionally to a specific symbol. Persists across sessions and is surfaced by run_pipeline in future sessions. Call it after solving something non-obvious.
save_observation(content="retry uses exponential backoff, max 3 attempts", symbol_fqn="src/http.rs::HttpClient::send")
generate_module_docs — write CLAUDE.md files per directory
Generates per-directory CLAUDE.md summaries from the symbol graph — types, functions, and (for Swift directories) Xcode MCP guidance. Pass write_files=true to write them to disk.
generate_module_docs(write_files=true)
| Situation | Tool |
|---|---|
| About to edit anything | run_pipeline |
| About to rename / move / delete | get_impact_graph first |
| Unfamiliar file, need the shape | get_skeleton |
| Reviewing a PR | get_diff_capsule |
| How does A call B? | search_logic_flow |
| Is the index ready? | index_status |
| Starting a new session | get_session_context |
| Just solved something tricky | save_observation |
| Setting up a new project | generate_module_docs |
codesurgeon index # Index (or re-index) workspace
codesurgeon status # Symbol/edge/file counts
codesurgeon search "retry logic" # BM25 search
codesurgeon skeleton src/http.rs # File skeleton
codesurgeon impact src/http.rs::send # Blast radius
codesurgeon flow src/http.rs::send src/retry.rs::with_retry # Logic flow
codesurgeon diff - < my.patch # Diff-aware capsule (stdin)
git diff | codesurgeon diff - # Pipe from git diff
codesurgeon diff "$(git diff)" # Inline diff text
codesurgeon context "fix auth bug" # Full run_pipeline from CLI
codesurgeon config # Show current configuration
codesurgeon docs # Generate per-module CLAUDE.md files
codesurgeon memory # List saved observations (shows IDs)
codesurgeon memory --delete <id> # Delete an observation by ID
codesurgeon observe "insight text" # Save a manual observation
codesurgeon observe "insight" --symbol src/http.rs::send # Attach to a symbol
codesurgeon submit-lsp-edges edges.json # Push LSP-resolved type edges from a file
cat edges.json | codesurgeon submit-lsp-edges # …or from stdin
| Language | Parser | Notes |
|---|---|---|
| Rust | tree-sitter | Full AST incl. impl/trait |
| Python | tree-sitter | Full AST |
| TypeScript / TSX | tree-sitter | Full AST; optional resolved types via TS compiler shim |
| JavaScript / JSX | tree-sitter | Full AST; optional resolved types via TS compiler shim |
| Swift | tree-sitter + Xcode MCP (optional) | Full AST — class/struct/enum/extension/protocol/func/method; Xcode MCP adds resolved types |
| Shell (bash/zsh) | tree-sitter | Function extraction |
| HTML | tree-sitter | Script/style blocks |
| SQL | tree-sitter | CREATE TABLE/VIEW/FUNCTION/INDEX/TYPE |
codesurgeon's tree-sitter pass gives you full TypeScript/JavaScript symbol structure. For resolved types (e.g. Promise<User> instead of Promise<any>), enable the optional compiler shim:
Requirements: node on PATH, tsconfig.json in your workspace root, and typescript in node_modules (or globally installed).
Enable by adding to .codesurgeon/config.toml:
[indexing]
ts_types = true
At index time codesurgeon invokes a bundled Node.js script (ts-enricher.js) that runs ts.createProgram() + TypeChecker over your workspace and annotates symbols with their resolved return/property types. The results are stored in the index as resolved_type and surfaced in context capsules.
Incremental: the shim only re-runs when tsconfig.json changes. Existing annotations are preserved across re-indexes.
Plain JS: the shim sets allowJs: true, so JSDoc-annotated JavaScript files are resolved correctly too.
VS Code users: if you have the codesurgeon VS Code extension installed, the submit_lsp_edges tool pushed from the running TypeScript language server is the faster alternative — no subprocess spawning required. ts_types is the right choice for CI, Codex, or non-VS Code editors.
codesurgeon's tree-sitter pass gives you full Swift symbol structure. For resolved types and live build diagnostics, pair it with Xcode MCP (Xcode 26+):
# Enable in Xcode: Settings → Intelligence → Enable Model Context Protocol
xcrun mcpbridge install --claude-code
When Xcode MCP is configured, run_pipeline on Swift files will note its availability
and agents can call its tools for type-resolved details. When it's absent, run_pipeline
says so explicitly — the tree-sitter graph remains fully usable for semantic search,
impact analysis, and session memory. index_status always reports whether Xcode MCP
was detected.
For Xcode < 26 or SPM-only projects: XcodeBuildMCP or xcode-mcp-server.
codesurgeon is fully local-first. Your code never leaves your machine.
.codesurgeon/index.db alongside your project (gitignored by default)The only binary that runs is codesurgeon-mcp, started by your MCP client (Claude Code / Codex) as a subprocess over stdio. It reads your source files, builds a local index, and responds to tool calls — nothing else.
Symptom: Tools like run_pipeline are not available, or Claude reports the MCP server failed to start.
CS_WORKSPACE points to an existing directory:
echo $CS_WORKSPACE
ls "$CS_WORKSPACE"
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' \
| CS_WORKSPACE=/path/to/project timeout 5 ./target/release/codesurgeon-mcp
A healthy server replies with an initialize response on stdout. Any error on stderr explains the failure.~/.claude.json (Claude Code CLI v2.x):
claude mcp list
Symptom: index_status() returns 0 symbols, or results look stale after editing files.
index_status() again to confirm.CS_WORKSPACE=/path/to/project codesurgeon index
CS_WORKSPACE=/path/to/project codesurgeon status
Symptom: A second Claude Code window or parallel Codex probe connects but sees no results, or logs show "serving read-only".
This is expected behaviour. Only one codesurgeon-mcp instance per workspace runs background indexing (the first one to acquire the PID lock). Subsequent instances serve the existing index read-only — they won't write new embeddings or trigger re-indexing. This is intentional to avoid concurrent index writes.
If you want the new instance to become the primary, stop the existing one first:
kill $(cat /path/to/project/.codesurgeon/mcp.pid)
Symptom: After a hard kill or power loss, new instances unexpectedly enter read-only mode.
codesurgeon auto-detects this: on startup it reads the existing PID file and runs kill -0 <pid> to check whether that process is actually alive. If it's dead, the stale file is overwritten automatically and the new instance becomes primary. No manual cleanup is needed in normal cases.
If for some reason this fails (e.g. the PID was reused by a system process), delete the file manually:
rm /path/to/project/.codesurgeon/mcp.pid
cargo buildSymptom: codesurgeon or codesurgeon-mcp command not found.
The binaries are placed in target/release/, not on your PATH automatically. Either use the full path:
/path/to/codesurgeon/target/release/codesurgeon-mcp
Or add the release directory to your PATH, or symlink:
ln -s /path/to/codesurgeon/target/release/codesurgeon /usr/local/bin/codesurgeon
Set CS_LOG (a tracing-subscriber env-filter
expression) to see detailed output from the MCP server or CLI. Default: warn.
# Info-level (recommended for troubleshooting)
CS_LOG=info CS_WORKSPACE=/path/to/project codesurgeon query "my search"
# Debug-level (verbose — shows every file indexed, every query scored)
CS_LOG=debug CS_WORKSPACE=/path/to/project ./target/release/codesurgeon-mcp
# Trace a specific module
CS_LOG=cs_core::engine=debug codesurgeon query "my search"
codesurgeon is configured via .codesurgeon/config.toml in your project root.
A user-level fallback at ~/.config/codesurgeon/config.toml is also loaded
(workspace settings take precedence). All settings are optional — sensible
defaults apply when files are missing.
[context]
# Token budget per context capsule (default: 4000)
max_tokens = 4000
# How much body text to include for adjacent (skeleton) symbols:
# "minimal" — ~5% of body (signatures only, very tight)
# "standard" — ~15% of body (default)
# "detailed" — ~30% of body (for large-context models like claude-opus)
skeleton_detail = "standard"
[indexing]
# Enable TypeScript compiler enrichment (requires node + typescript in node_modules)
ts_types = false
# Enable Pyright type enrichment (requires pyright on PATH)
python_pyright = false
# Enable cargo-expand macro enrichment (requires cargo-expand)
rust_expand_macros = false
# Enable rustdoc JSON type enrichment (requires nightly Rust)
rust_rustdoc_types = false
[memory]
# Auto-observations expire after this many days (default: 7)
auto_ttl_days = 7
# Manual observations never expire by default; set to override
# manual_ttl_days = 90
[git]
# Write manifest.json for git-tracked index metadata
track_manifest = false
[observability]
# USD cost per token for savings display in `codesurgeon stats` (default: 0.000003)
token_rate_usd = 0.000003
Run codesurgeon config to see the effective merged settings and their sources.
Most settings live in config.toml (above). The following env vars control
runtime concerns that don't belong in committed config:
| Var | Read by | Purpose |
|---|---|---|
CS_WORKSPACE | codesurgeon, codesurgeon-mcp | Workspace root for indexing and queries. Required when not running from inside the workspace. |
CLAUDE_CODE_WORKSPACE | codesurgeon, codesurgeon-mcp | Alias of CS_WORKSPACE, set automatically by Claude Code. CS_WORKSPACE wins if both are set. |
CS_LOG | codesurgeon, codesurgeon-mcp | tracing-subscriber env-filter expression (e.g. info, debug, cs_core::engine=trace). Default: warn. |
CS_TRACK_MANIFEST | codesurgeon, codesurgeon-mcp | Set to 1 to overlay [git] track_manifest = true from the environment, omitting manifest.json from .codesurgeon/.gitignore so it can be shared across clones. |
CS_BENCH_CENTRALITY_K | cargo run --example token_savings | Pin the centrality smoothing constant k for the 20-query bench, e.g. CS_BENCH_CENTRALITY_K=15.0 reproduces pre-#82 behaviour. Unset → corpus-derived (default). Bench-only — has no effect on the binaries. |
Contributions are welcome! Before submitting a PR, run the pre-commit checklist:
cargo fmt --all # Format
cargo clippy --workspace -- -D warnings # Lint (warnings are errors in CI)
cargo test --workspace # Tests
All three must pass. See .github/workflows/ci.yml for the exact CI checks.
MIT — see LICENSE for details.
190 commits
Rust
99.2%