Skip to content
Independent product. Not affiliated with or endorsed by Anthropic.

The patch tool

Editing a file by naming the region instead of quoting it back, and every reason it can refuse.

Edit asks for old_string to reproduce the target text byte for byte. That is the one field where a model re-emits, as output tokens, text it already paid for as input tokens. A thirty-line old_string costs thirty lines of output and carries no information the file did not already have.

The patch tool removes that repetition. Claude names the region; the tool reads the region off disk and replaces it.

Naming a region

Two selectors, and only one may be used at a time.

Selector Example Means
lines "42:58" Lines 42 through 58 inclusive, counted by newline.
regex {"pattern": "def run\\(.*?\\n\\n", "flags": "s"} The single region the expression matches.

Lines are counted by \n and nothing else. A form feed in a C or Emacs Lisp source would otherwise shift every line number, because the usual line splitter also breaks on \f, \v and several Unicode separators.

It runs on your machine

The tool is served by culp mcp, a stdio server inside the CLI that Claude Code starts. It is local because a remote server cannot read your disk, and routing the file's text through the model's output would re-emit exactly what the feature avoids.

The tool cannot check that the file was read first, because it is a separate process with no view of the transcript. Edit can and does. That is a real reduction in safety, taken deliberately for the tokens, and the receipt is what makes a mistargeted region visible. Read the receipt.

What it will not do

Nothing is authored. The region replaced is always a substring of the file, byte for byte. Regions are never widened, because widening changes what the replacement has to contain, and a region that cannot be told apart is refused by name rather than guessed at.

The replacement is spliced at the resolved offsets, never searched for. An earlier version applied it by string replacement, which found the first copy of the region's text, so a line range could resolve correctly and then edit a different line whenever the file repeated itself.

Refusals

Reason What happened
line_out_of_range The range names a line the file does not have.
no_match The expression matched nothing.
ambiguous_match The expression matched in more than one place.
divergent_matches The matches disagree about what the region is.
invalid_regex The pattern did not compile.

A refusal costs a turn and never a file. The replacement is encoded in full first, written to a sibling temporary, and only then moved over the original, so a failure part-way through cannot leave the file truncated. Symlinks are followed rather than replaced.

Text handling

The stream is decoded as UTF-8 by the tool itself rather than by the platform, because a piped standard input is otherwise decoded with the system locale. On a Windows console that turned a Japanese character into three wrong ones, and turned é into mojibake silently, under a receipt reporting success.

Line breaks inside the replacement are converted to the file's own convention. A file with no newline, or one that already mixes both, has shown no convention and gets nothing imposed on it.