How to Perform Structural Replace in Code-Graph-RAG

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 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. 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.

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.

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 (line 109), this executes the actual transformation.

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 (lines 1072-1082), enabling remote invocation.

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 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), 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.
  • 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 defines the data structure for tracking modifications.
  • Access identical functionality via the MCP API endpoint registered in 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. 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.

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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →