# How AST-Based Surgical Patching with Diff Preview Works in Code-Graph-RAG

> Learn how AST-based surgical patching in Code-Graph-RAG precisely locates code blocks, previews diffs, and applies changes atomically for reliable updates. Explore the technique today.

- Repository: [Vitali Avagyan/code-graph-rag](https://github.com/vitali87/code-graph-rag)
- Tags: internals
- Published: 2026-08-13

---

**AST-based surgical patching combines Tree-sitter parsing with diff-match-patch algorithms to locate exact code blocks, generate unified diff previews, and atomically apply changes only after validation.**

Code-Graph-RAG implements a precision editing workflow that enables LLMs to modify source code safely through AST-based surgical patching with diff preview. This system, located in the `vitali87/code-graph-rag` repository, leverages Tree-sitter for robust code extraction and the diff-match-patch library for fail-safe text replacement. The architecture ensures that only intended code blocks are modified while providing complete visibility into changes before they are committed.

## The Three-Stage Surgical Pipeline

The `FileEditor` class in [`codebase_rag/tools/file_editor.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tools/file_editor.py) orchestrates the patching process through three distinct phases: AST-driven location, diff generation with preview, and validated application.

### Stage 1: Locating Target Blocks via Tree-sitter

Before any text manipulation occurs, the system identifies the precise code block to modify. The `get_parser` method (lines 43-48) initializes a Tree-sitter parser specific to the file's language, loading grammar definitions via `load_parsers()`.

When the request specifies a function or class name, the system traverses AST nodes using `get_function_source_code`, matching against `function_node_types` and `class_node_types` constants. This AST traversal extracts the exact source snippet while accounting for language-specific syntax, ensuring the `target_block` string is retrieved reliably regardless of minor whitespace variations or comments.

### Stage 2: Generating Diff Previews

Once the target block is identified, the system prepares the modification through the `get_diff` method (lines 63-86). This method generates a human-readable preview using Python's `difflib.unified_diff` to create a standard Git-style diff output.

Internally, the `replace_code_block` method (lines 10-52) constructs the modified content by executing `original_content.replace(target_block, replacement_block, 1)`. It then utilizes the `diff_match_patch` library to create a patch object via `self.dmp.patch_make(original_content, modified_content)`.

The resulting diff displays line-by-line changes showing removed lines prefixed with `-` and added lines with `+`, allowing the LLM or user to verify the exact scope of the modification before committing to disk.

### Stage 3: Safe Patch Application

The final phase applies the patch only after rigorous safety checks. The `patch_apply` method from the diff-match-patch library executes the transformation, returning a tuple of `(new_content, results)` where `results` is a boolean array indicating success for each patch chunk.

In `replace_code_block` (lines 44-46), the system verifies that all results are `True` before proceeding. If any chunk fails to apply cleanly, the operation aborts and logs a warning via the `EDITOR_PATCH_FAILED` constant from [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py).

## Safety Mechanisms and Validation

The surgical patcher implements multiple guardrails to prevent accidental modifications:

- **Path Resolution**: The requested `file_path` is resolved against the project root, with explicit checks for `full_path.is_file()` (lines 15-21).
- **Existence Verification**: The system verifies that the exact `target_block` string exists in the original content; if absent, the operation fails immediately (lines 25-28).
- **Single Replacement**: Even if the target block appears multiple times, only the first occurrence is replaced, emitting a warning for duplicate matches (lines 30-33).
- **Atomic Writes**: Upon successful patch validation, the new content is written atomically to the file system, preventing corruption from partial writes (lines 48-50).

## Practical Implementation Example

The following example demonstrates the complete workflow using the `FileEditor` class:

```python
from codebase_rag.tools.file_editor import FileEditor

# Initialize the editor with project root

editor = FileEditor(project_root="my_repo")

# Define the exact block to replace

target = """def greet(name):
    print(f"Hello, {name}")"""

# Define the replacement code

replacement = """def greet(name):
    # Added logging

    logger.info(f"Greeting {name}")
    print(f"Hello, {name}")"""

# Generate diff preview before applying

diff_preview = editor.get_diff(
    file_path="src/utils.py",
    function_name="greet",
    new_code=replacement,
)
print("Proposed changes:\n", diff_preview)

# Apply the surgical patch if preview is acceptable

success = editor.replace_code_block(
    file_path="src/utils.py",
    target_code=target,
    replacement_code=replacement,
)
print(f"Patch applied successfully: {success}")

```

## Summary

- **AST-driven precision**: Tree-sitter parsers locate target blocks reliably across Python, Java, Go, and other languages supported by `load_parsers()`.
- **Diff-match-patch safety**: The `diff_match_patch` library ensures text replacements apply cleanly, with `patch_apply` validation preventing partial modifications.
- **Human-readable previews**: The `get_diff` method generates unified diffs via `difflib.unified_diff`, showing exact line changes before commitment.
- **Atomic operations**: File writes occur only after all validation checks pass, ensuring either complete success or no change.
- **Repository location**: All functionality resides in [`codebase_rag/tools/file_editor.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tools/file_editor.py), with logging constants referenced from [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py) and [`codebase_rag/logs.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/logs.py).

## Frequently Asked Questions

### How does the AST parser improve patch accuracy in Code-Graph-RAG?

The AST parser improves accuracy by resolving function or class names to exact source text blocks through Tree-sitter's language-specific grammar trees. When a request specifies `function_name="greet"`, the `get_function_source_code` method walks `function_node_types` nodes to extract the precise text span, eliminating ambiguity from manual line number calculations or whitespace variations.

### What happens if the target code block appears multiple times in the file?

If the target block exists multiple times, `replace_code_block` replaces only the first occurrence and emits a warning via the logging system. The `replace` operation uses a count of `1` (lines 30-33 in [`file_editor.py`](https://github.com/vitali87/code-graph-rag/blob/main/file_editor.py)), ensuring deterministic behavior while alerting the user to potential duplicates that might require separate handling.

### Can the diff preview be generated without applying the patch?

Yes, the `get_diff` method (lines 63-86) operates independently of `replace_code_block`, allowing LLMs or developers to inspect the unified diff output before deciding to apply changes. This separation enables iterative refinement of the `replacement_block` until the diff preview shows exactly the intended modifications.

### What error handling exists if a patch fails to apply?

If `patch_apply` returns any `False` values in its results array, the operation aborts before writing to disk and logs the failure using the `EDITOR_PATCH_FAILED` message template. The original file remains unmodified because the atomic write only occurs after verifying all patch chunks succeeded, preventing partial or corrupted file states.