npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

patch-file-tool

v1.0.0

Published

Atomic exact-match file-surgery tool and MCP server for AI agent runtimes.

Downloads

138

Readme

AgenticEconomy 🛠️

A zero-dependency core, atomic file-surgery tool for AI Agents. Natively supports programmatic TypeScript imports and the Model Context Protocol (MCP).

Stop letting your agents execute full-file rewrites that burn tokens and increase latency. AgenticEconomy enforces an exact-match patching mechanism that guarantees predictable, lightweight workspace edits.

🚀 Quick Start (MCP Configuration)

Add this to your client configuration (for example Claude Desktop, Cursor, or Windsurf) to integrate the tool instantly:

{
  "mcpServers": {
    "agentic-economy": {
      "command": "npx",
      "args": ["-y", "patch-file-tool"]
    }
  }
}

Set PATCH_FILE_WORKSPACE_ROOT in the MCP server environment when your client supports it. If omitted, the server uses its current working directory as the workspace sandbox.

📦 Programmatic Usage (TypeScript)

import { patchFile } from "patch-file-tool";

const result = await patchFile({
  filePath: "src/index.ts",
  searchBlock: "const x = 1;",
  replaceBlock: "const x = 2;",
}, { workspaceRoot: process.cwd() });

Why This Exists

AI agents often waste tokens and introduce corruption by emitting entire replacement files for small edits. Full-file rewrites can accidentally drop imports, comments, generated sections, formatting, or user changes that appeared after the agent last read the file.

patch_file makes the safer path the default: send only the smallest exact original block that identifies the edit, plus the replacement block. Exact-once matching prevents fuzzy or partial edits from landing in the wrong place.

The MCP tool uses three snake_case fields: file_path, search_block, and replace_block. The programmatic TypeScript API accepts those names plus ergonomic camelCase aliases: filePath, searchBlock, and replaceBlock.

Token and Latency Comparison

For small edits in large files, patch_file keeps the agent response proportional to the edit instead of proportional to the whole file. The exact token count depends on the tokenizer, model, and payload, so this repository includes a reproducible benchmark instead of relying on estimates.

Run it locally:

npm run tokens

Benchmark fixture:

  • tokenizer: gpt-tokenizer/model/gpt-4o
  • file: synthetic 1,000-line TypeScript file
  • edit: one line changed at line 500

Measured output-token counts:

| Strategy | Agent output | Exact output tokens | Output characters | Latency profile | Failure mode | | --- | ---: | ---: | ---: | --- | --- | | Full-file rewrite | Entire 1,000-line file | 9,002 | 31,894 | Slowest: model must generate, transmit, and the runtime must write the whole file | Can drop unrelated lines, stale edits, comments, formatting, or concurrent user changes | | Unified diff | Diff hunk with line metadata | 99 | 339 | Moderate: compact output, but patch application may need parsing and hunk matching | Can fail or misapply if line numbers/context are stale or generated hunks are malformed | | patch_file | Minimal exact search_block plus replace_block | 48 | 156 | Fastest for small edits: model emits only the necessary text and the engine does one exact match | Fails closed if the block is missing or not unique |

Example payload for the same one-line change:

{
  "file_path": "src/generated-config.ts",
  "search_block": "export const setting0500 = 500;\n",
  "replace_block": "export const setting0500 = 9001;\n"
}

That payload is small enough for an agent loop to retry cheaply. If the file changed, the tool returns a structured error instead of guessing, and the agent can reread only the relevant file content before trying again. End-to-end model latency still depends on the provider and model, but output generation and transmission scale directly with these measured output-token counts.

How Exact-Once Matching Works

  1. The target file is read from disk.
  2. search_block is matched with strict string matching.
  3. No whitespace normalization, fuzzy matching, or partial patching is performed.
  4. If the block appears exactly once, that single occurrence is replaced.
  5. If the block appears zero times or more than once, nothing is written.

For normal text block replacement, occurrences are counted as non-overlapping exact matches.

Installation and Local Usage

npm install
npm run build
npm test

During local development:

npm run typecheck
npm run clean

TypeScript Usage

import { patchFile, PATCH_FILE_ERROR_CODES } from "patch-file-tool";

const result = await patchFile(
  {
    file_path: "src/config.ts",
    search_block: "export const retries = 2;\n",
    replace_block: "export const retries = 3;\n",
  },
  { workspaceRoot: process.cwd() },
);

if (!result.ok) {
  if (result.code === PATCH_FILE_ERROR_CODES.SEARCH_BLOCK_NOT_FOUND) {
    // Reread the file and retry with exact current text.
  }

  console.error(result.code, result.message);
}

Public exports:

  • patchFile
  • PATCH_FILE_ERROR_CODES
  • patchFileSchema
  • PatchFileInput
  • PatchFileOptions
  • PatchFileResult
  • PatchFileSuccess
  • PatchFileFailure
  • PatchFileErrorCode
  • PatchFileSchema

MCP Usage

This package also includes a stdio MCP server that exposes the same engine as a tool named patch_file.

Build it first:

npm run build

Run the MCP server:

PATCH_FILE_WORKSPACE_ROOT=/path/to/workspace npx patch-file-mcp

For local development from this repository:

PATCH_FILE_WORKSPACE_ROOT=/path/to/workspace node dist/mcp-server.js

Example Codex MCP config:

[mcp_servers.patch_file]
command = "node"
args = ["/path/to/patch-file-tool/dist/mcp-server.js"]

[mcp_servers.patch_file.env]
PATCH_FILE_WORKSPACE_ROOT = "/path/to/workspace"

PATCH_FILE_WORKSPACE_ROOT is the sandbox root. If it is omitted, the MCP server uses its current working directory.

JSON Schema

The schema is exported as patchFileSchema and is also available at schemas/patch_file.schema.json.

{
  "name": "patch_file",
  "description": "Safely edit one file by replacing one exact block of current text with replacement text. Use this instead of rewriting whole files.",
  "parameters": {
    "type": "object",
    "additionalProperties": false,
    "required": ["file_path", "search_block", "replace_block"],
    "properties": {
      "file_path": {
        "type": "string",
        "description": "Path to the file to edit, constrained by the configured workspace/root directory."
      },
      "search_block": {
        "type": "string",
        "minLength": 1,
        "description": "Exact original text currently present in the file. Copy it exactly from the current file, preserving indentation and line endings. Provide only the minimal lines needed to uniquely identify the edit, with enough surrounding context so this block appears exactly once. Avoid full-file rewrites. If the tool reports zero matches or multiple matches, reread the file and retry with a larger or more precise search_block."
      },
      "replace_block": {
        "type": "string",
        "description": "Replacement text to insert in place of search_block. It may be empty. Preserve intended indentation and line endings inside this block. Avoid full-file rewrites; replace only the minimal exact block needed for the edit."
      }
    }
  }
}

Success Result

{
  "ok": true,
  "file_path": "/workspace/src/config.ts",
  "replacements": 1,
  "line_number": 1,
  "before_chars": 26,
  "after_chars": 26,
  "before_bytes": 26,
  "after_bytes": 26
}

Failure Results

SEARCH_BLOCK_NOT_FOUND means the file was not modified:

{
  "ok": false,
  "code": "SEARCH_BLOCK_NOT_FOUND",
  "message": "search_block was not found. Reread the file and retry with exact current text plus minimal surrounding context.",
  "file_path": "/workspace/src/config.ts",
  "match_count": 0
}

SEARCH_BLOCK_AMBIGUOUS means the file was not modified:

{
  "ok": false,
  "code": "SEARCH_BLOCK_AMBIGUOUS",
  "message": "search_block matched multiple locations. Retry with additional surrounding context so the block is unique.",
  "file_path": "/workspace/src/config.ts",
  "match_count": 3
}

Other stable error codes include:

  • INVALID_INPUT
  • PATH_OUTSIDE_WORKSPACE
  • TARGET_IS_DIRECTORY
  • BINARY_FILE_REJECTED
  • FILE_READ_ERROR
  • FILE_WRITE_ERROR

Retry Guidance for Agents

When a patch fails, do not guess and do not switch to a full-file rewrite.

  • On SEARCH_BLOCK_NOT_FOUND, reread the file, copy the exact current text, and retry with minimal context.
  • On SEARCH_BLOCK_AMBIGUOUS, include a few more surrounding lines so search_block appears exactly once.
  • Preserve indentation and line endings inside both blocks.
  • Keep search_block as small as possible while still unique.
  • Use an empty replace_block when deleting text.

Security Notes

patchFile(input, { workspaceRoot }) constrains edits to the configured workspace root. If no root is provided, the current working directory is used.

The engine:

  • rejects path traversal outside the workspace;
  • rejects absolute paths outside the workspace;
  • rejects symlinks that resolve outside the workspace;
  • rejects directories;
  • rejects likely binary files;
  • preserves existing file permissions where practical;
  • writes temporary files in the same directory as the target file;
  • cleans temporary files after write failures;
  • replaces files with a same-directory rename;
  • uses best-effort file and directory sync where supported by the platform.

Limitations

  • The tool edits local filesystem paths only.
  • It is intentionally strict: no fuzzy matching, no regex mode, and no whitespace normalization.
  • Binary detection is conservative and rejects files containing NUL bytes in the sampled prefix.
  • Atomic replacement is as strong as practical in Node.js and the host filesystem, but durability semantics vary by operating system and filesystem.
  • Encoding preservation currently covers UTF-8, UTF-8 with BOM, UTF-16LE with BOM, and UTF-16BE with BOM.

Compared With Unified Diffs

Unified diffs are excellent for human review and version-control workflows, but agents can produce malformed hunks, stale line numbers, or patches that require fuzzy application. patch_file uses a smaller contract: replace this exact current text if and only if it is unique.

Compared With Normal Search/Replace

Normal search/replace tools often replace every match, the first match, or a fuzzy match. patch_file refuses to write unless there is exactly one strict match, which makes failures safe and machine-readable.

License

MIT. See LICENSE.