Roo Code Diff Strategy System: How Multi-Search-Replace Handles File Edits
The Roo Code diff strategy system implements a pluggable architecture centered on the MultiSearchReplace strategy, which processes any number of independent search-replace blocks in a single request, applying them sequentially with fuzzy matching and indentation preservation.
Roo Code, an open-source AI coding assistant from RooCodeInc/Roo-Code, abstracts all file modifications behind a diff strategy system. This architecture delegates editing operations to strategy implementations that translate structured diff payloads into final file content. The system centers on the DiffStrategy interface, which the default MultiSearchReplaceDiffStrategy implements to handle complex multi-part edits.
How the Diff Strategy System Works
At its core, the diff strategy system defines a contract through the DiffStrategy interface in src/shared/tools.ts. This interface requires three methods: applyDiff, getName, and getProgressStatus.
When a task executes, src/core/task/Task.ts instantiates the strategy and attaches it to the task context:
this.diffStrategy = new MultiSearchReplaceDiffStrategy()
Every apply_diff tool call forwards its diff parameter to this strategy (line 534), which then handles the transformation logic independently of the task orchestration.
Multi-Search-Replace Syntax and Structure
The MultiSearchReplace strategy expects a specific marker syntax derived from Git conflict notation but optimized for AI-generated edits:
<<<<<<< SEARCH
:start_line:5
-------
exact text to find
=======
replacement text
>>>>>>> REPLACE
The :start_line: directive is optional but recommended—it indicates where the search block is expected, enabling faster exact matching. Content can include escaped markers using a leading backslash when these sequences appear literally in code. Multiple blocks can be concatenated in a single request, and the strategy processes them independently and in order of start line, ensuring deterministic left-to-right application.
Processing Multiple Search-Replace Operations
The applyDiff method in src/core/diff/strategies/multi-search-replace.ts handles multiple operations through a six-stage pipeline:
Step 1: Parse and Sort Blocks
The strategy first extracts all search-replace blocks using a regex matcher (lines 289-293):
matches = [...diffContent.matchAll(/(?:^|\n)(?<!\\)<<<<<<</g)]
It then sorts blocks by their :start_line: value. This sorting guarantees that later replacements see the effects of earlier edits, maintaining logical consistency when multiple changes affect the same file.
Step 2: Locate Matches with Fallback Logic
For each block, the strategy attempts three matching approaches in sequence (lines 783-904, 997-1014, and 1019-1035):
- Exact Match: When
:start_line:is provided, verify content at that specific location - Fuzzy Search: If exact similarity falls below the configurable threshold, perform a buffered middle-out search within
BUFFER_LINES(40 lines) of context - Aggressive Stripping: Remove line numbers and retry matching if previous methods fail
Step 3: Validation Guards
Before applying any change, the strategy validates the block (lines 38-57 and 51-67):
- Rejects identical search and replace content
- Blocks empty search strings
- Validates marker sequencing through
validateMarkerSequencing
Step 4: Apply with Indentation Preservation
Upon validation, the strategy captures the original indentation of matched lines, then preserves relative indentation for each replacement line (lines 666-698). It builds a new resultLines array while maintaining a running delta to adjust indices for subsequent blocks (lines 506-508). This ensures replacement text maintains structural alignment with the original file regardless of the indentation present in the diff payload.
Fuzzy Matching Implementation
The fuzzy matching system uses Levenshtein distance to calculate similarity:
Similarity = 1 - (distance / maxLength)
This calculation resides in the getSimilarity function (lines 9-31). The fuzzyThreshold parameter defaults to 1.0 for exact matches but is configurable through the UI, which presents the scale as "0% → 1.0 (exact)". The BUFFER_LINES constant of 40 provides context windows before and after the supplied :start_line:, keeping search operations performant while accommodating minor code drift.
Practical Example: Two Independent Replacements
Consider updating both a logging statement and a function return value in one request:
const diff = `
<<<<<<< SEARCH
:start_line:12
-------
console.log("old value");
=======
console.log("new value");
>>>>>>> REPLACE
<<<<<<< SEARCH
:start_line:45
-------
function foo() { return 1; }
=======
function foo() { return 2; }
>>>>>>> REPLACE
`;
const { success, content, failParts } = await applyDiffTool({
path: "src/example.ts",
diff,
});
The first block updates line 12, while the second targets line 45. Because the strategy sorts by start_line and maintains a running delta, the second replacement automatically accounts for any line shifts caused by the first edit.
Key Files in the Diff Strategy Subsystem
Understanding the complete architecture requires examining these specific files:
-
src/core/diff/strategies/multi-search-replace.ts: Core implementation containingMultiSearchReplaceDiffStrategywith fuzzy matching, indentation preservation, and block processing logic -
src/shared/tools.ts: Declares theDiffStrategyinterface, registers available strategies, and defines theapply_difftool contract -
src/core/task/Task.ts: Task orchestration that instantiates the diff strategy (line 534) and routes tool calls to the appropriate handler -
src/webview-ui/src/utils/parseUnifiedDiff.ts: Frontend parser for unified diff format, enabling the UI to render pending edits -
src/webview-ui/src/utils/highlightDiff.ts: Syntax highlighting component that uses the same marker conventions as the backend strategy
Summary
- Roo Code implements a pluggable diff strategy architecture centered on the
DiffStrategyinterface - The default
MultiSearchReplacestrategy handles any number of search-replace blocks in a single request - Blocks are sorted by start line and applied sequentially with a running delta to maintain index accuracy
- Fuzzy matching with configurable thresholds and 40-line buffering accommodates minor code drift
- Indentation preservation ensures replacement text maintains structural alignment with original code
- Per-block failure reporting enables granular error handling and targeted retry attempts
Frequently Asked Questions
What is the default diff strategy in Roo Code?
Roo Code uses the MultiSearchReplaceDiffStrategy as its default and currently only shipped implementation. According to the source code in src/core/task/Task.ts, this strategy is instantiated for every task and handles all apply_diff tool invocations by implementing the DiffStrategy interface with applyDiff, getName, and getProgressStatus methods.
How does Roo Code handle multiple search-replace blocks in one request?
The strategy parses all blocks using regex extraction, sorts them by their optional :start_line: directive, and processes them sequentially. It maintains a running delta variable that adjusts line indices for subsequent blocks, ensuring that earlier edits shift the target locations of later edits appropriately. This deterministic left-to-right application prevents conflicts when multiple changes affect the same file.
What happens if the search text doesn't match exactly?
If exact matching fails or similarity falls below the fuzzyThreshold, the strategy falls back to a buffered middle-out fuzzy search within 40 lines of the specified start position. If that fails, it attempts an aggressive line-number stripping pass. The similarity calculation uses Levenshtein distance normalized by maximum length, configurable via the UI from 0% to 100% (1.0 exact).
How does the diff strategy preserve code indentation?
During replacement, the strategy captures the original indentation of the matched search block, then applies that indentation to each line of the replacement content (lines 666-698 in multi-search-replace.ts). This preserves the relative indentation structure, ensuring that inserted code maintains the same nesting level and alignment as the code it replaces, regardless of the indentation present in the diff payload itself.
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 →