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
Truefor preview mode; set toFalseto 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-grepbinary and checks availability viahas_ast_grep()independencies.py. - Create tool instances using
create_structural_editor_tool()with anAstGrepServiceand optionalReadContentRecord. - Use
dry_run=Trueto preview diffs without touching files; setdry_run=Falseto apply changes permanently. - The
StructuralReplaceChangemodel incodebase_rag/types_defs.pydefines the data structure for tracking modifications. - Access identical functionality via the MCP API endpoint registered in
mcp/tools.pyfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →