How to Prevent LLM from Making Unwanted Changes to Unrelated Code: The Surgical Changes Method
The "Surgical Changes" principle from the forrestchang/andrej-karpathy-skills repository mandates that every changed line must trace directly to the user's request, preventing LLMs from refactoring adjacent code, changing formatting, or adding unnecessary imports.
When using large language models for code generation, scope creep is a persistent risk—models frequently "improve" nearby comments, reindent blocks, or refactor perfectly functional abstractions while ostensibly fixing a bug. The andrej-karpathy-skills repository formalizes a defense against this behavior called Surgical Changes, a strict editing discipline that keeps diffs minimal and purposeful.
Understanding the Surgical Changes Principle
According to the source code in CLAUDE.md (lines 53-66) and the skill definition in skills/karpathy-guidelines/SKILL.md (lines 35-48), Surgical Changes is a constraint-based workflow that requires an LLM to edit only the specific code necessary to fulfill a user's explicit request. The guideline defines the compliance test as follows: "Every changed line should trace directly to the user's request." This single rule eliminates tangential improvements, stylistic "cleanups," and speculative refactors.
The Five Rules of Surgical Editing
The repository codifies surgical precision into five enforceable constraints:
- Edit only what the task demands – Do not "improve" adjacent code, update comments for clarity, or fix formatting in nearby lines. This keeps the diff minimal and ensures version control history accurately reflects intent.
- Don't refactor un-broken code – Leave existing abstractions, variable names, and function signatures exactly as-is unless the request explicitly requires a structural change. This prevents accidental side-effects from restructuring code the model does not fully understand.
- Match the existing style – Use the same indentation depth, naming conventions, and comment patterns as the surrounding codebase. This prevents style-driven churn that can obscure the functional change during review.
- If you create orphans, clean them up – Remove imports, variables, or functions that become unused as a direct consequence of your change, but do not remove pre-existing dead code that might serve a future purpose. This keeps the repository tidy without over-reaching.
- Every changed line must trace to the user's request – Perform a final sanity-check before submitting: if you cannot justify a modified line by referencing the original prompt, revert that line.
Code Examples: Non-Surgical vs. Surgical Changes
Example 1: The "Improvement" Trap (Violating the Rule)
The following diff violates the surgical principle by touching existing comments, changing formatting, and adding an unrequested dependency:
- // Existing helper
- export function formatDate(date: Date): string {
- return date.toISOString().split('T')[0];
- }
-
- // New feature request: add a helper to format a timestamp
+ // Existing helper (unchanged)
+ export function formatDate(date: Date): string {
+ return date.toISOString().split('T')[0];
+ }
+
+ // New feature request implementation
+ export function formatTimestamp(ts: number): string {
+ // Unrelated refactor: replace `new Date` with a library call
+ return dayjs.unix(ts).format('YYYY-MM-DD');
+ }
This change fails compliance because it modifies existing comments, adds an unnecessary dayjs import, and refactors the implementation using an external library when the request only asked for a timestamp helper.
Example 2: A Minimal, Compliant Patch
The following diff respects the surgical guidelines by adding only the requested functionality without touching adjacent code or introducing new dependencies:
+ // New feature request implementation
+ export function formatTimestamp(ts: number): string {
+ // Directly follow the request: convert UNIX seconds to ISO date string
+ const d = new Date(ts * 1000);
+ return d.toISOString().split('T')[0];
+ }
This patch is surgical because it leaves existing helpers untouched, uses native methods available in the current scope, and every added line directly serves the user's request.
Automating Surgical Change Validation
You can programmatically enforce these rules using a validation layer. The following pseudo-code demonstrates how a Claude-Code plugin (as referenced in CLAUDE.md) could block non-surgical diffs before they reach your codebase:
function isSurgicalChange(diff) {
// 1. Ensure diff touches only files explicitly mentioned
if (!diff.files.some(f => request.targets.includes(f))) return false;
// 2. Reject modifications to lines that were not part of the request
for (const hunk of diff.hunks) {
if (hunk.type !== 'add' && !request.allowedEdits.includes(hunk.line)) {
return false;
}
}
// 3. Verify no new imports were added unless requested
if (diff.addedImports.some(i => !request.requestedImports.includes(i))) return false;
return true;
}
Embedding this check in your LLM pipeline prevents scope creep at the automation layer, ensuring only minimal, targeted patches pass validation.
Key Source Files in the Repository
The authoritative definitions for surgical editing live in two specific locations within forrestchang/andrej-karpathy-skills:
CLAUDE.md– Contains the complete set of four Karpathy-inspired principles, with the full "Surgical Changes" specification at lines 53-66.skills/karpathy-guidelines/SKILL.md– Provides the formal skill definition used by Claude-Code plugins, mirroring the surgical-changes rules in a concise format at lines 35-48.
These files serve as the canonical reference for implementing surgical precision in LLM-generated code edits.
Summary
- Surgical Changes require that every modified line trace directly to an explicit user request, preventing LLM scope creep.
- The principle is defined in
CLAUDE.md(lines 53-66) andSKILL.md(lines 35-48) of theforrestchang/andrej-karpathy-skillsrepository. - Key constraints include: no refactoring of working code, no style changes, and mandatory cleanup of orphaned imports only when caused by the change.
- Automated guardrails can validate diffs programmatically by checking file targets, line modifications, and import additions against the original request.
Frequently Asked Questions
What exactly constitutes an unrelated code change?
An unrelated change is any modification to lines, imports, or formatting that is not strictly required to satisfy the user's explicit request. According to the guideline in CLAUDE.md, if you cannot draw a direct line from a changed line back to the prompt, that change is unrelated and must be reverted. This includes cosmetic improvements to comments, renaming variables for "clarity," or switching implementation details to use a preferred library.
Why should LLMs avoid refactoring working code during feature implementation?
Refactoring un-broken code introduces unnecessary risk. The repository's SKILL.md warns that LLMs should not restructure abstractions they do not fully understand, as this can create subtle bugs, break dependent systems, or expand the review surface area far beyond the intended feature. Surgical editing keeps the blast radius of any change strictly limited to the requested functionality.
How can I enforce surgical changes in my development workflow?
You can implement the validation pseudo-code provided in the repository's examples as a pre-commit hook or a Claude-Code plugin. This script checks that diffs only touch targeted files, do not add unrequested imports, and only modify lines explicitly allowed by the request. Additionally, requiring human reviewers to verify that "every changed line traces to the request" creates a cultural check against scope creep.
What should I do if my change makes existing imports or variables unused?
The surgical rule for orphan cleanup dictates that you must remove imports, variables, or helper functions that become obsolete specifically because of your change. However, you must not remove pre-existing dead code that was already unused before your edit, as it may serve a future purpose or remain for backward compatibility. Focus only on the debris generated by your current task.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →