better-edit-tools Documentation#

better-edit-tools is reliable file-editing infrastructure for coding agents. It validates model-generated edits, writes atomically, explains failures, and provides recovery paths instead of blindly overwriting files.

This site is organized around three questions:

  • How do I use the MCP server, CLI, or Go library?
  • How does the editor detect stale or unsafe model-generated edits?
  • Why were the current validation, recovery, and protocol behaviors chosen?

The documentation provides usage guides, reliability design notes, historical decisions, and Go API references.

A Note for AI Agents / LLMs#

Every page on this site is available in two raw formats for easy fetching and analysis:

  • Markdown source: Replace index.html at the end of any page URL with index.md. For example:
    • HTML page: /en/decisions/
    • Markdown source: /en/decisions/index.md
  • Site summary llms.txt: Visit llms.txt for titles, descriptions, and Markdown source links of all pages.

If you find an error in the documentation or want to discuss a historical decision, click the Open issue button on the page; it will automatically include the docs:talk label.

Start here#

Project README#

better-edit-tools#

中文 | English

Reliable file-editing infrastructure for coding agents, implemented as a small Go-native MCP server, CLI, and library. It validates model-generated edits, writes atomically, explains failures, and provides recovery paths instead of blindly overwriting files. Experimental project: tool names, parameters, and behaviors may change as the design evolves. Prefer capability-based or dynamically resolved tool selection in prompts. Tool descriptions and error messages are English-only because they are consumed by LLMs.

Coding agents often try to edit a file after the file has changed since it was read. A reliable editor therefore needs more than a write operation: it needs a way to identify the intended range, verify assumptions, preserve the original on failure, and tell the agent what to do next.

Why this exists#

better-edit-tools is built around the following editing loop:

be-read
  |
  +--> current content + viewed_code_id
              |
              v
be-replace / be-insert / be-delete
              |
              +--> old content hard check
              +--> viewed_code_id consistency signal
              |
              +--> atomic write on success
              +--> re-read, retry, rollback, or recover on failure

The project treats model mistakes as an engineering input, not as an exceptional possibility. Its reliability mechanisms include:

  • exact old content validation before a targeted replacement;
  • session-range validation through viewed_code_id;
  • atomic file writes and preview mode;
  • actionable error messages that suggest the next tool call;
  • transaction snapshots and chip-based recovery for failed operations;
  • structure-aware range and balance detection that avoids strings and comments.

See Reliable Editing for Coding Agents for the design rationale and failure model.

If you are a Go developer who wants to embed editing capabilities directly in your agent framework, see the Go API documentation.

🤖 Want an AI agent to install and configure the binary for you? See the LLM self-setup guide. 📜 For historical decisions and closed feature proposals, see the decision log.

To have an AI agent install it for you:

install this mcp server:https://conglinyizhi.github.io/better-edit-tools-mcp/llms.txt

Tools#

be-balance#

Structural sanity check for brackets, braces, parentheses, HTML/XML tag closure, and quote parity. The scanner avoids interference from strings and comments. The verbose parameter controls output detail:

  • false (default): only outputs unmatched items.
  • true: outputs all matched pairs.

——Catch structural mistakes early, even when the file mixes code, markup, and strings.

be-read#

Read-only source inspection tool. Prints file content with line numbers. Pass a positive end value for an explicit range, or 0 or negative to auto-expand to the enclosing function scope. Returns a viewed_code_id (v0.4+) that can be passed to be-replace for line-number validation.

When embedding the Go library directly, prefer the Read API name.

——Read the exact slice you need without guessing the enclosing function range.

be-replace#

Precise line-range substitution. Accepts a viewed_code_id parameter from a prior be-read session to validate that line numbers still match. When old is provided, the tool verifies current content before writing and returns an error on mismatch. The server also accepts old_text as an alias.

——Replace a known block with minimal movement and minimal surprise.

be-insert#

Adds content after a specified line. after_line=0 inserts at the very beginning of the file. The preferred primitive for incremental edits — avoids rewriting unrelated lines. The sole parameter for insertion position is after_line, replacing the old ambiguous line/after_line dual param.

——Insert new content exactly where it belongs without touching the rest of the file.

be-insert-chip#

Inserts content from a file (file:///absolute/path) or a previously saved chip cache (chip://{id}). When from is omitted, lists all available chip IDs. This tool bridges the gap between failed operations and recovery: when be-write fails due to malformed JSON and saves its arguments as a chip, be-insert-chip can replay that content directly into the target file.

——Replay cached arguments from a prior failure, or inject file content at a precise line.

be-delete#

Removes a line range using start/end line numbers or a target descriptor. Line-oriented for predictable, easy-to-reason-about results. Legacy aliases (start_line, end_line, line, lines) have been removed to eliminate tool confusion.

——Remove targets with line-level precision and predictable results.

be-write#

Raw file write tool for full-content replacement. Accepts both single-file and multi-file payloads via direct arguments:

  • Single file: {"file":"...","content":"..."}
  • Multi file: {"files":[{"file":"...","content":"..."}]}

A degraded parsing path is automatically invoked when standard JSON parsing fails, rescuing AI-generated content with broken escaping. Literal \n in content is auto-detected and converted to real newlines, solving the double-encoding problem in MCP call chains.

——Even when the JSON wrapper breaks, the write still tries to rescue the payload.

be-func-range#

Detects the enclosing {} block or function range for a given line. Uses brace counting with string- and comment-aware scanning for reliability on real-world source code.

——Find the logical function boundary instead of guessing from raw braces alone.

be-tag-range#

Finds the enclosing XML/HTML/Vue tag pair for a line. The markup-oriented counterpart to be-func-range.

——Locate the surrounding tag pair that defines the real editing boundary.

Design highlights#

  • Atomic writes: File modifications go through a temp-file-then-rename cycle, preventing data corruption if the process crashes mid-write.
  • isError signaling: Errors properly report isError: true per the MCP spec.
  • Go-native: No runtime dependencies — a single binary with a small embedded editing library.
  • Fault-tolerant JSON parsing: AI-generated content often contains backticks, ${}, or unescaped quotes; be-write automatically falls back to character-level extraction.
  • Session state bridging: be-read returns a viewed_code_id that be-replace can accept to validate consistent line numbering.
  • English-only descriptions: tool descriptions are written once in English; LLM clients are natively multilingual, so description language does not affect understanding.

Usage#

Build#

go build -o better-edit-tools ./cmd/better-edit-tools

The binary will be at ./better-edit-tools.

Run#

./better-edit-tools

Add --no-prefix to strip the be- prefix from tool names (e.g., be-read becomes read). This is useful for MCP controllers that cannot re-edit tool names.

Register in an MCP client#

Add to your MCP client configuration:

{
  "mcpServers": {
    "better-edit-tools": {
      "command": "/path/to/better-edit-tools/better-edit-tools"
    }
  }
}

For example, Claude Desktop’s config is at ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows).

CLI usage#

The same binary can be used as a command-line tool. When invoked with a subcommand, it executes a single operation and exits; otherwise it starts the MCP server as usual.

# Read
./better-edit-tools read --file main.go --start 1 --end auto

# Replace
./better-edit-tools replace --file main.go --start 5 --end 10 --content "..."

# Insert
./better-edit-tools insert --file main.go --after-line 4 --content "..."

# Delete
./better-edit-tools delete --file main.go --start 5 --end 10

# Write
./better-edit-tools write --file main.go --content "package main\n\nfunc main() {}"

# Balance / scope detection
./better-edit-tools balance --file main.go
./better-edit-tools func-range --file main.go --line 12
./better-edit-tools tag-range --file index.html --line 8

Use --output json to get machine-parseable output, and --preview to see the diff without writing to disk.

./better-edit-tools read --file main.go --start 1 --end 10 --output json
./better-edit-tools replace --file main.go --start 5 --end 10 --content "..." --preview

Note: viewed_code_id and snapshot/transaction tools are MCP-only because they rely on in-process session state.

Install#

The helper script downloads the latest release for your OS and architecture, verifies the SHA-256 checksum, and installs the binary into ~/.local/share/better-edit-tools/bin/. Pass a tag name to install a specific version.

bash <(curl -fsSL https://raw.githubusercontent.com/conglinyizhi/better-edit-tools-mcp/main/scripts/install.sh)
bash <(curl -fsSL https://raw.githubusercontent.com/conglinyizhi/better-edit-tools-mcp/main/scripts/install.sh) v0.2

Release assets are published for Linux, macOS, and Windows on both amd64 and arm64, with matching .sha256 checksum files. Windows releases are packaged as .zip files. Release notes are grouped from Conventional Commits.

Acknowledgements#

The replace, insert, and delete operations are inspired by includewudi/fast-edit.

License#

MIT