How to Use Refactoring Tools for Symbol Renaming in code-review-graph
Use the three-step graph-backed workflow in code-review-graph to safely rename symbols: preview the changes with rename_preview(), inspect the generated refactor_id, and apply edits via apply_refactor() with optional dry-run support.
The code-review-graph repository provides graph-backed refactoring tools that enable safe, accurate symbol renaming across entire Python codebases. Unlike simple text replacement, these tools leverage the repository's knowledge graph to track every definition, call site, and import relationship. This guide explains how to use refactoring tools for symbol renaming in code-review-graph through both the CLI and Python API.
The Three-Step Graph-Backed Workflow
The refactoring implementation in code_review_graph/refactor.py follows a strict preview-then-apply pattern to prevent accidental modifications.
Step 1: Preview the Rename
The rename_preview() function traverses the knowledge graph to locate the symbol definition and all reachable references. It constructs a list of edits targeting CALLS, IMPORTS_FROM, and REFERENCES edges that static search tools often miss.
According to the source code in code_review_graph/refactor.py (lines 73-85), this function:
- Queries the graph store for the symbol's definition node
- Collects all inbound edges to determine affected files
- Stores the pending operation in a thread-safe
_pending_refactorsdictionary - Returns a JSON object containing a unique
refactor_id, edit list, and statistics
Step 2: Inspect the Preview
Each preview receives a unique identifier (e.g., a1b2c3d4) that persists for 600 seconds (REFACTOR_EXPIRY_SECONDS = 600). The preview JSON includes:
- The list of files to be modified
- Line-by-line edit coordinates
- Safety validation status (path traversal checks at lines 53-57)
Step 3: Apply the Rename
Supply the refactor_id to apply_refactor() to execute the edits. As implemented in code_review_graph/refactor.py (lines 86-95), this function:
- Validates the
refactor_idexists in_pending_refactors - Writes changes to source files (or returns diffs if
dry_run=True) - Automatically clears the preview from memory after successful application (lines 14-22)
Why Graph-Backed Refactoring Matters
Accuracy – The knowledge graph captures dynamic import relationships and cross-module references that grep-based tools cannot resolve.
Safety – The 10-minute expiry window and path traversal validation (lines 53-57) prevent stale or malicious refactor operations from executing.
Dry-Run Support – Set dry_run=True in apply_refactor() (lines 34-42) to receive unified diffs without modifying disk, enabling code review before committing changes.
CLI Implementation
The command-line interface in code_review_graph/cli.py exposes the refactoring workflow through two sub-commands.
The refactor sub-command (lines 42-46 and 92-99) forwards requests to refactor_func(mode="rename", ...) in code_review_graph/tools/refactor_tools.py. The apply_refactor sub-command invokes apply_refactor_func() (lines 33-38) to execute pending operations.
Code Examples
CLI Workflow
Generate a preview and apply the rename through the terminal:
# Step 1 – Preview the rename operation
code-review-graph refactor rename \
--old-name helper \
--new-name new_helper
# Response includes refactor_id for the next step
{
"status": "ok",
"summary": "Rename preview: helper -> new_helper, 5 edit(s). Use apply_refactor_tool(refactor_id='a1b2c3d4') to apply.",
"refactor_id": "a1b2c3d4",
"edits": [ … ]
}
# Step 2 – Review changes without writing (dry-run)
code-review-graph apply_refactor a1b2c3d4 --dry-run
# Step 3 – Execute the rename
code-review-graph apply_refactor a1b2c3d4
Python API
Use the core functions directly from scripts or notebooks:
from code_review_graph.refactor import rename_preview, apply_refactor
from code_review_graph.graph import GraphStore, find_project_root
# Initialize the graph store
root = find_project_root()
store = GraphStore(root)
# 1️⃣ Generate preview
preview = rename_preview(store, old_name="helper", new_name="new_helper")
if preview is None:
raise RuntimeError("Symbol not found in graph")
print(f"Preview ID: {preview['refactor_id']} – {len(preview['edits'])} edits")
# 2️⃣ Dry-run to inspect diffs
dry = apply_refactor(preview['refactor_id'], root, dry_run=True)
print(dry['diffs']['src/module.py'])
# 3️⃣ Apply changes
result = apply_refactor(preview['refactor_id'], root, dry_run=False)
print(f"Applied {result['applied']} edit(s) to {len(result['files_modified'])} file(s)")
Programmatic Wrapper
For tool integration, use the convenience functions in refactor_tools.py:
from code_review_graph.tools.refactor_tools import refactor_func, apply_refactor_func
# Preview via wrapper
preview = refactor_func(mode="rename", old_name="helper", new_name="new_helper")
refactor_id = preview["refactor_id"]
# Dry-run then apply
apply_refactor_func(refactor_id, dry_run=True)
apply_refactor_func(refactor_id)
Summary
- Core Implementation:
rename_preview()andapply_refactor()live incode_review_graph/refactor.py, using a thread-safe_pending_refactorscache with 600-second expiry. - Graph Accuracy: The tool analyzes CALLS, IMPORTS_FROM, and REFERENCES edges to find all symbol occurrences, including dynamic imports.
- Safety Features: Path traversal validation and mandatory preview steps prevent unauthorized or accidental file modifications.
- CLI Integration:
code_review_graph/cli.pyexposesrefactorandapply_refactorcommands that delegate torefactor_tools.pywrappers. - Dry-Run Support: Both the API and CLI support
dry_runmode to preview unified diffs before committing changes.
Frequently Asked Questions
How does the graph improve renaming accuracy compared to text search?
The knowledge graph tracks semantic relationships through CALLS, IMPORTS_FROM, and REFERENCES edges. According to the code_review_graph/refactor.py implementation, rename_preview() traverses these edges to locate definition sites and all consuming code, capturing dynamic imports and cross-module usage that static grep patterns would miss.
What is the refactor_id and how long does it remain valid?
The refactor_id is a unique identifier generated during the preview phase and stored in _pending_refactors. As defined by REFACTOR_EXPIRY_SECONDS = 600 in the source, previews expire after 10 minutes. The ID must be supplied to apply_refactor() within this window before the cache entry is invalidated.
Can I review changes before modifying source files?
Yes. Both the Python API and CLI support dry-run mode. In code_review_graph/refactor.py (lines 34-42), setting dry_run=True in apply_refactor() returns unified diffs without writing to disk. The CLI exposes this via the --dry-run flag on the apply_refactor sub-command.
Which source files contain the core refactoring logic?
The primary logic resides in code_review_graph/refactor.py (functions rename_preview and apply_refactor). CLI command definitions are in code_review_graph/cli.py (lines 42-46 and 92-99), while convenience wrappers are implemented in code_review_graph/tools/refactor_tools.py (lines 33-38). Graph store utilities are imported from code_review_graph/graph.py.
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 →