Skip to main content
Glama

surgical ✂️

Enforce Karpathy's Rule #3. Automatically prune AI diff bloat and over-editing before you commit.

When you ask an AI coding agent to fix a 2-line bug, research by Tongyao Zhu, Wei Hern Lim, and Min-Yen Kan shows it routinely rewrites 40–100 lines: renaming variables in unrelated files, reordering imports, and touching working code you never asked it to touch (arXiv:2609.04061). That over-editing shows up in any stack—Next.js, FastAPI, Go, Rust, SQL migrations—especially on generic names like page.tsx, main.py, app.py, utils.ts, and lib.rs.

surgical is a language-agnostic MCP server and CLI. It audits uncommitted Git changes against your stated intent using Universal Lexical Topology (sub-word tokens, an identifier graph, and cosmetic normalization)—not per-language parsers or fragile filenames—and strips unrequested drive-by refactors before you commit.

Zero network dependencies. Operates 100% locally on your Git working tree in <5ms. No Python runtime, no tree-sitter, no extra language tooling.

(Currently in pre-release testing — install directly from source).


The Rule We Enforce

Andrej Karpathy's Rule #3 for Coding Agents:
"Surgical Changes Only — touch only what was asked, never refactor adjacent code, one diff one scope."


Related MCP server: Git Code Review MCP

Why Filename Heuristics Fail

Most naive diff cleaners check filenames against keywords in your prompt. That breaks immediately on modern apps:

  • In the Next.js App Router, almost every file is named page.tsx, layout.tsx, or route.ts.

  • Shared logic lives in utils.ts, helpers.ts, lib.rs, utils.py, or helpers.go.

  • In Python services (FastAPI, Django, Flask), the same trap is main.py, app.py, models.py, and config.py.

If your prompt is "Fix the mobile navbar", a filename matcher will blindly discard app/page.tsx and break your build. If it is "Add a /healthz endpoint", the same matcher will drop main.py or keep an unrelated models.py because the filename looks "important."

How surgical beats filenames (Universal Lexical Topology)

  1. Sub-word tokenizer: camelCase, PascalCase, snake_case, kebab-case, and SCREAMING_SNAKE are split into stems. Prompt "Fix mobile navbar toggle"{mobile, navbar, toggle}. That matches NavbarToggle, navbar_toggle, and toggle_nav() in TypeScript, Python, Go, or Rust.

  2. Identifier graph (no import parsing): Novel identifiers are taken from seed hunks that match the intent. Files that share those identifiers are KEEP. Files with zero overlap to the seed cluster are BLOAT.

  3. Cosmetic normalization: Comments (//, #, --, /* */, """ """, ''' ''') and whitespace are stripped. If before equals after, the hunk is formatter churn (black / isort / prettier / gofmt / rustfmt) and is pruned even if it contains identifiers.

Generic-file examples (main.py, app.py, page.tsx, utils.ts) are scored by hunk content and identifier overlap—not by path.

FastAPI example (same engine, any language)

Intent: Add a /healthz endpoint.

Change

Verdict

Why

main.py@app.get("/healthz") def health_check(): return {"status": "ok"}

Keep (surgical)

Sub-word tokens match healthz, even though the filename is generic.

utils/db.py — helper health_check uses (check_db_connection)

Keep (connected)

Identifier graph: the endpoint and helper share identifiers.

routers/auth.py — unsolicited JWT validation refactor + import reorder

Prune (bloat)

Isolated island; zero identifier overlap with the /healthz seed cluster.

config.py — Black formatting-only cosmetic changes

Prune (cosmetic)

After comment/whitespace strip, before == after.

A polyglot commit is the same: Python navbar_toggle, Go NavbarToggle, and TypeScript NavbarToggle stay; an unrelated SQL index and prettier-only CSS are pruned.


1. Quick Setup (From Source)

Requires Node.js 18+ and Git.

git clone https://github.com/preprint-labs/surgical.git
cd surgical
npm install
npm run build

Verify that dist/index.js was created.


2. Editor Setup (Cursor, Claude Code, GitHub Copilot)

Because you built from source, point your editor to your local dist/index.js binary.

Find your full script path:

  • Windows (PowerShell): (Resolve-Path dist\index.js).Path

  • macOS / Linux: pwd/dist/index.js


A. Cursor Setup

Add to your project's .cursor/mcp.json:

{
  "mcpServers": {
    "surgical": {
      "command": "node",
      "args": ["<FULL_PATH_TO_SURGICAL>/dist/index.js"]
    }
  }
}

(On Windows, use escaped backslashes: "C:\\path\\to\\surgical\\dist\\index.js").

Option 2: Cursor GUI

  1. Open Settings (Ctrl + Shift + J or Cmd + Shift + J) -> Features -> MCP.

  2. Click + Add New MCP Server.

  3. Set:

    • Name: surgical

    • Type: command

    • Command: node <FULL_PATH_TO_SURGICAL>/dist/index.js


B. Claude Code (Terminal CLI)

Run this single command in your terminal:

# macOS/Linux:
claude mcp add surgical -- node /absolute/path/to/surgical/dist/index.js

# Windows:
claude mcp add surgical -- node "C:\path\to\surgical\dist\index.js"

C. GitHub Copilot (VS Code)

Add to your workspace .vscode/settings.json:

{
  "github.copilot.chat.mcpServers": {
    "surgical": {
      "command": "node",
      "args": ["<FULL_PATH_TO_SURGICAL>/dist/index.js"]
    }
  }
}

3. Automated Agent Enforcement (Zero Human Friction)

You do not need to run terminal commands manually while coding.

Add the snippet below to your project's .cursorrules, CLAUDE.md, or .github/copilot-instructions.md to force your AI assistant to audit and clean up its own diff before finishing. The same instruction works for Next.js, FastAPI, Go, Rust, and everything else.

# Karpathy Rule #3: Surgical Changes Only
Before declaring a task complete, you MUST call the `prune_diff_bloat` MCP tool passing the user's original request as the `intent`.
Generic files (`page.tsx`, `main.py`, `app.py`, `utils.ts`, `lib.rs`) are scored by hunk tokens and identifier overlap—not filenames.
Keep intent-matching and identifier-connected changes. Confirm reversion of isolated drive-by refactors and cosmetic-only diffs (formatter churn).

4. CLI Usage (For Manual Inspection)

You can also run surgical directly from the command line outside an editor:

# Explain what belongs to your intent without touching the working tree
node dist/index.js explain --intent "add navbar to homepage"

# Same scoring on any language (generic app.py / main.py / page.tsx is not discarded)
node dist/index.js explain --intent "add /healthz endpoint"

node dist/index.js explain --intent "fix mobile navbar toggle"

# Plan and non-destructively stage only the matching surgical files
node dist/index.js prune --intent "add navbar to homepage"

# Revert confirmed unrequested drive-by refactors
node dist/index.js prune --intent "add navbar to homepage" --auto-discard

Command

Behavior

explain --intent <text>

Prints a dry-run explanation of why each file/hunk is marked surgical vs. bloat.

prune --intent <text>

Non-destructively runs git add on verified surgical files, leaving bloat unstaged.

prune --auto-discard

Reverts unrequested bloat files after safety snapshotting.

MCP tools: prune_diff_bloat, explain_diff, undo_pruning.


5. Safety & Zero Data Loss Guarantee

surgical is designed to be safe by default:

  1. Automatic Safety Snapshot: Before any mutation or discard, surgical runs git stash create / git write-tree in <5ms. Your entire pre-pruned state is saved as an immutable Git tree object.

  2. Non-Destructive Staging: By default, prune only stages the surgical files (git add), leaving questionable files unstaged for human review.

  3. Instant Undo: If a file was pruned that you wanted to keep, run:

    node dist/index.js undo

    (or call the MCP tool undo_pruning) to instantly restore your working tree.


6. Running Tests

The test suite uses a polyglot fixture (Python + Go + TypeScript + unrelated SQL + cosmetic CSS) and a FastAPI /healthz story (main.py + connected utils/db.py vs. isolated JWT churn in routers/auth.py and Black-only config.py):

npm test

Citation

If you reference this tool or the over-editing evaluation methodology, please cite the underlying research:

@article{overediting2026,
  title={When Models Edit Too Much: On the Fidelity of Minimal Code Edits},
  author={Zhu, Tongyao and Lim, Wei Hern and Kan, Min-Yen},
  journal={arXiv preprint arXiv:2609.04061},
  year={2026}
}

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to intelligently organize Git changes into clean, focused commits with autopilot mode or surgical line-by-line staging precision. Supports partial staging of untracked files and handles large diffs with smart truncation.
    5
    1
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables AI assistants to perform code reviews by providing access to staged files, git diffs, and repository file content. It allows users to evaluate changes and context within any local git repository before committing or pushing.
    3
    4 npm
    ISC
  • A
    license
    A
    quality
    A
    maintenance
    Enables verification of AI coding agent self-reports against git diff truth and a deterministic gate, producing pass/regenerate/reject directives to ensure claimed work matches actual changes.
    6
    AGPL 3.0