# How to Perform Structural Replace in Code-Graph-RAG

> Learn to perform structural replace in Code-Graph-RAG using AST-grep patterns and rewrite templates for efficient codebase refactoring. Preview changes with dry-run options.

- Repository: [Vitali Avagyan/code-graph-rag](https://github.com/vitali87/code-graph-rag)
- Tags: how-to-guide
- Published: 2026-09-04

---

**Code-Graph-RAG provides a built-in structural replace tool that matches AST-grep patterns and applies rewrite templates to refactor codebases with optional dry-run previews and taint-tracking capabilities.**

Code-Graph-RAG ships with a powerful structural replacement system that leverages the `ast-grep` engine to perform semantic code transformations. This functionality allows you to refactor code by matching abstract syntax tree patterns rather than simple text strings, ensuring precise modifications across your codebase. The tool is implemented in [`codebase_rag/tools/structural_editor.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tools/structural_editor.py) and integrates with both the Python API and the MCP (Memory-Centric Processor) interface.

## Prerequisites and Dependencies

Before executing a structural replace, verify that the `ast-grep` binary is installed on your system. The codebase checks availability via `has_ast_grep()` in [`codebase_rag/utils/dependencies.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/utils/dependencies.py). If the binary is missing from the PATH, the tool returns `AST_GREP_NOT_AVAILABLE` and cannot proceed.

## Initializing the Structural Editor Tool

To begin programmatic refactoring, instantiate an `AstGrepService` and create the tool using the factory function. You may optionally provide a `ReadContentRecord` to track changes for the egress taint gate.

```python
from codebase_rag.tools.structural_editor import create_structural_editor_tool
from codebase_rag.tools.ast_grep_service import AstGrepService
from codebase_rag.taint import ReadContentRecord

service = AstGrepService()                 # Wraps the ast-grep binary

read_record = ReadContentRecord()            # Optional, records diffs for taint-gate

structural_tool = create_structural_editor_tool(service, read_record)

```

## Understanding the Replace Parameters

The underlying `structural_replace` coroutine accepts four key arguments:

- **pattern** – An AST-grep pattern with metavariables (e.g., `print($A)`).
- **rewrite** – A template string where captured variables are substituted (e.g., `log($A)`).
- **language** – Optional language hint such as `"python"` or `"typescript"`.
- **dry_run** – Boolean flag defaulting to `True` for preview mode; set to `False` to apply changes.

## Dry-Run vs. Live Replacement

### Previewing Changes Safely

When `dry_run=True` (the default), the tool returns a diff without modifying any files. This mode allows you to review the impact of your pattern before committing changes.

```python
preview = await structural_tool.function(
    pattern="print($A)",
    rewrite="log($A)",
    language="python",
    dry_run=True,
)
print(preview)   # Shows diff preview, no files edited

```

### Applying Changes to Disk

Set `dry_run=False` to permanently rewrite matched files. As shown in [`codebase_rag/tests/test_structural_tools.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tests/test_structural_tools.py) (line 109), this executes the actual transformation.

```python
result = await structural_tool.function(
    pattern="print($A)",
    rewrite="log($A)",
    language="python",
    dry_run=False,
)
print(result)    # Diff shown and files rewritten

```

## MCP API Integration

For HTTP-based workflows, the same functionality is exposed as an MCP endpoint. The `MCPTools` class wires the handler to `self._structural_editor_tool` in [`codebase_rag/mcp/tools.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/mcp/tools.py) (lines 1072-1082), enabling remote invocation.

```python
from codebase_rag.mcp.client import MCPClient

client = MCPClient(base_url="http://localhost:8000")
response = client.structural_replace(
    pattern="print($A)",
    rewrite="log($A)",
    language="python",
    dry_run=False,
)
print(response)   # JSON payload containing the diff

```

## Interpreting the Output

The `format_changes()` function in [`structural_editor.py`](https://github.com/vitali87/code-graph-rag/blob/main/structural_editor.py) constructs the human-readable response. It includes either `AST_GREP_DRY_RUN_HEADER` or `AST_GREP_APPLIED_HEADER`, followed by match counts and diffs for each changed file. When a `ReadContentRecord` is provided, the diff data is recorded within it (see lines 60-64 in [`structural_editor.py`](https://github.com/vitali87/code-graph-rag/blob/main/structural_editor.py)), allowing the egress taint gate to review modifications before they exit the system.

## Summary

- The structural replace tool requires the `ast-grep` binary and checks availability via `has_ast_grep()` in [`dependencies.py`](https://github.com/vitali87/code-graph-rag/blob/main/dependencies.py).
- Create tool instances using `create_structural_editor_tool()` with an `AstGrepService` and optional `ReadContentRecord`.
- Use `dry_run=True` to preview diffs without touching files; set `dry_run=False` to apply changes permanently.
- The `StructuralReplaceChange` model in [`codebase_rag/types_defs.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/types_defs.py) defines the data structure for tracking modifications.
- Access identical functionality via the MCP API endpoint registered in [`mcp/tools.py`](https://github.com/vitali87/code-graph-rag/blob/main/mcp/tools.py) for remote operations.

## Frequently Asked Questions

### What is the difference between structural replace and regex replacement?

Structural replace operates on the abstract syntax tree using AST-grep patterns, ensuring you match semantic code structures rather than text patterns. This prevents false positives from matching strings inside comments or unrelated variable names that happen to contain similar text.

### How do I verify that ast-grep is installed before running the tool?

Call `has_ast_grep()` from [`codebase_rag/utils/dependencies.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/utils/dependencies.py). This function returns a boolean indicating whether the binary is available on the system PATH, preventing runtime errors when attempting structural operations.

### Can I track which files were modified for security auditing?

Yes. Pass a `ReadContentRecord` instance when creating the tool via `create_structural_editor_tool()`. The tool automatically records all diffs in this object during execution, enabling the egress taint gate to review changes before they leave the system, as implemented in lines 60-64 of [`structural_editor.py`](https://github.com/vitali87/code-graph-rag/blob/main/structural_editor.py).

### Does the structural replace tool support languages other than Python?

Yes. The `language` parameter accepts any identifier supported by ast-grep, including `"typescript"`, `"javascript"`, `"rust"`, and others. Omitting the parameter allows ast-grep to infer the language from file extensions automatically.