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_refactors dictionary
  • 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_id exists 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() and apply_refactor() live in code_review_graph/refactor.py, using a thread-safe _pending_refactors cache 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.py exposes refactor and apply_refactor commands that delegate to refactor_tools.py wrappers.
  • Dry-Run Support: Both the API and CLI support dry_run mode to preview unified diffs before committing changes.

Frequently Asked Questions

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:

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 →