# How to Implement File Editing Using the str_replace Tool in Codebuff

> Learn how to implement file editing using Codebuff's str_replace tool. Apply exact-match string replacements programmatically with JSON or the TypeScript SDK and get unified diffs.

- Repository: [Codebuff/codebuff](https://github.com/CodebuffAI/codebuff)
- Tags: how-to-guide
- Published: 2026-03-09

---

**The str_replace tool in Codebuff applies exact-match string replacements to files and returns a unified diff, enabling programmatic file editing through JSON payloads or the TypeScript SDK.**

To implement file editing using the str_replace tool in Codebuff, you need to understand its architecture across the monorepo. The tool is defined in the `common` package, handled by the `agent-runtime`, and consumed by the CLI or custom agents. It performs exact-match replacements with optional indentation handling and generates unified diffs for verification.

## Understanding the str_replace Tool Architecture

### Core Components and File Locations

The implementation spans several packages in the Codebuff repository:

- **[`common/src/tools/params/tool/str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/common/src/tools/params/tool/str-replace.ts)** – Defines the Zod schema for inputs (`path`, `replacements`) and outputs (`file`, `message`, `unifiedDiff`). This schema validates that each replacement contains `old`, `new`, and optional `allowMultiple` boolean.

- **[`packages/agent-runtime/src/tools/handlers/tool/str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/packages/agent-runtime/src/tools/handlers/tool/str-replace.ts)** – Contains the `handleStrReplace` function that orchestrates file reading, delegates to the core processor, and streams results back to the client.

- **[`packages/agent-runtime/src/process-str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/packages/agent-runtime/src/process-str-replace.ts)** – Houses the `processStrReplace` function, which performs the actual text replacement, normalizes line endings (`\r\n` to `\n`), handles indentation via `tryToDoStringReplacementWithExtraIndentation`, and generates diffs using `diff.createPatch`.

- **[`cli/src/utils/implementor-helpers.ts`](https://github.com/CodebuffAI/codebuff/blob/main/cli/src/utils/implementor-helpers.ts)** – Provides `constructDiffFromReplacements` for rendering human-readable diffs in CLI timelines.

- **[`common/src/tools/list.ts`](https://github.com/CodebuffAI/codebuff/blob/main/common/src/tools/list.ts)** – Registers `str_replace` and `propose_str_replace` so agents can discover and invoke them.

### Data Flow Overview

When you implement file editing using the str_replace tool in Codebuff, the data flows through these stages:

1. **Invocation** – An agent or script creates a tool call with `cb_tool_name: "str_replace"` and an input payload matching the Zod schema.

2. **Handling** – The runtime routes the call to `handleStrReplace`, which fetches the current file content (or pending edits) and calls `processStrReplace`.

3. **Processing** – `processStrReplace` normalizes line endings, iterates over each replacement entry, and applies exact-match logic. If `allowMultiple` is `false` and multiple matches exist, it returns an error. If indentation differs, it attempts fuzzy matching via `tryToDoStringReplacementWithExtraIndentation`.

4. **Diff Generation** – The processor creates a unified diff using `createPatch`, stripping headers to return only the hunks.

5. **Response** – The handler streams the result back, including the new file content, success message, and `unifiedDiff` string.

## Implementing str_replace in Your Code

### Basic JSON Payload Structure

To invoke the tool directly, construct a JSON block following the schema defined in [`common/src/tools/params/tool/str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/common/src/tools/params/tool/str-replace.ts):

```json
{
  "cb_tool_name": "str_replace",
  "input": {
    "path": "src/utils/logger.ts",
    "replacements": [
      {
        "old": "export const logger = createLogger();",
        "new": "export const logger = createLogger({ level: 'debug' });",
        "allowMultiple": false
      }
    ]
  }
}

```

The `allowMultiple` parameter controls whether to replace all occurrences (`true`) or enforce a single match (`false`). When `false`, the tool returns an error if the `old` string appears more than once, preventing accidental mass replacements.

### TypeScript SDK Implementation

For programmatic access within the Codebuff ecosystem, use the SDK's `invokeTool` function:

```typescript
import { invokeTool } from '@codebuff/sdk';

const toolCall = {
  cb_tool_name: 'str_replace' as const,
  input: {
    path: 'src/util/logger.ts',
    replacements: [
      {
        old: 'export const logger = createLogger();',
        new: 'export const logger = createLogger({ level: "debug" });',
        allowMultiple: false,
      },
    ],
  },
};

const result = await invokeTool(toolCall);
console.log(result.unifiedDiff);

```

This approach routes through the runtime's `handleStrReplace` handler, ensuring proper file locking, diff generation, and error handling.

### Previewing Changes with propose_str_replace

Before committing changes, use `propose_str_replace` to generate a diff without writing to disk:

```json
{
  "cb_tool_name": "propose_str_replace",
  "input": {
    "path": "src/api.ts",
    "replacements": [
      {
        "old": "export function fetchData() {",
        "new": "export async function fetchData() {",
        "allowMultiple": false
      }
    ]
  }
}

```

The response includes `unifiedDiff` but leaves the filesystem untouched. After review, execute the identical payload with `str_replace` to apply the edit.

## Handling Edge Cases and Validation

The `processStrReplace` function in [`packages/agent-runtime/src/process-str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/packages/agent-runtime/src/process-str-replace.ts) includes robust handling for common editing pitfalls:

- **Line ending normalization** – Converts Windows `\r\n` to Unix `\n` internally, then restores the original line ending style in the output (lines 40-42).

- **Indentation tolerance** – When exact matches fail due to whitespace differences, `tryToDoStringReplacementWithExtraIndentation` attempts to align the replacement by adding or removing leading spaces (lines 52-60).

- **Multiple occurrence protection** – Unless `allowMultiple` is explicitly `true`, the tool errors if the search string appears more than once, preventing unintended global replacements (lines 41-46).

- **No-op detection** – If replacements result in identical content, the tool returns a "No change to the file" error rather than writing redundant data (lines 84-98).

## Rendering Diffs for User Interface

To display edits in a CLI timeline or custom interface, use the helper from [`cli/src/utils/implementor-helpers.ts`](https://github.com/CodebuffAI/codebuff/blob/main/cli/src/utils/implementor-helpers.ts):

```typescript
import { constructDiffFromReplacements } from '../../cli/src/utils/implementor-helpers';

const diff = constructDiffFromReplacements([
  { old: 'const x = 1;', new: 'const x = 2;' },
  { old: 'console.log("debug");', new: '' },
]);

console.log(diff);

```

This generates a Git-style diff view showing removed lines with `-` and added lines with `+`, suitable for terminal output or web rendering.

## Summary

- The **`str_replace`** tool in Codebuff provides atomic, exact-match file editing with built-in diff generation and validation.
- Implementation requires constructing a JSON payload with `path` and `replacements` array, or using the TypeScript SDK's `invokeTool` function.
- The architecture spans [`common/src/tools/params/tool/str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/common/src/tools/params/tool/str-replace.ts) for schemas, [`packages/agent-runtime/src/process-str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/packages/agent-runtime/src/process-str-replace.ts) for core logic, and [`cli/src/utils/implementor-helpers.ts`](https://github.com/CodebuffAI/codebuff/blob/main/cli/src/utils/implementor-helpers.ts) for UI rendering.
- Use **`propose_str_replace`** for dry-run previews, and leverage edge-case handling like indentation tolerance and multiple-occurrence protection to ensure safe edits.

## Frequently Asked Questions

### What is the difference between str_replace and propose_str_replace in Codebuff?

The `str_replace` tool writes changes directly to the filesystem and returns a unified diff, while `propose_str_replace` performs the same validation and diff generation without modifying the file. Use `propose_str_replace` when you need user approval or want to preview changes in a multi-step workflow before committing them.

### How does str_replace handle whitespace and indentation differences?

According to the source code in [`packages/agent-runtime/src/process-str-replace.ts`](https://github.com/CodebuffAI/codebuff/blob/main/packages/agent-runtime/src/process-str-replace.ts), the tool first attempts an exact match including whitespace. If that fails, it calls `tryToDoStringReplacementWithExtraIndentation` to adjust for leading spaces or tabs, allowing the replacement to succeed even when the indentation level differs between the search string and the actual file content.

### Can str_replace perform multiple replacements in a single file?

Yes, the `replacements` array in the input payload accepts multiple objects, each with `old`, `new`, and optional `allowMultiple` properties. However, for each individual replacement, `allowMultiple` controls whether that specific string can be replaced multiple times within the file. Setting it to `false` enforces a single match and returns an error if duplicates are found, preventing accidental mass replacements.

### What happens if the replacement does not change the file content?

The `processStrReplace` function explicitly checks for no-op edits. If the new content is identical to the original after processing all replacements, it returns an error with the message "No change to the file" rather than writing redundant data to disk. This prevents empty commits and unnecessary file system operations.