Workflow for safely renaming symbols (functions, types, classes, interfaces, constants, variables) across a codebase. Uses repo_map, batch_symbols, and build_check to ensure every consumer is updated and nothing breaks.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Workflow for safely renaming symbols (functions, types, classes, interfaces, constants, variables) across a codebase. Uses repo_map, batch_symbols, and build_check to ensure every consumer is updated and nothing breaks.
effort
small
generated_from_knowledge
[]
source_knowledge_ids
["20f7da40-02e0-4da8-9310-a78eb87ca81e"]
generated_at
2026-06-14T16:50:00.000Z
confidence
0.8
status
active
version
4
skill_origin
generated
provenance_note
Re-linked to current knowledge entries (version 4). The original source ID 1eb9f867... is no longer present in the active knowledge store. The skill body and behavior are unchanged; only source_knowledge_ids metadata was updated to point to the current lesson about updating test data when a fix changes expectations, which is directly relevant to safe rename verification.
Safe Rename Skill
Guides a systematic, tool-augmented workflow for renaming exported symbols across
a codebase without silently breaking consumers, tests, or downstream builds.
When to Use
Renaming an exported function, class, interface, type alias, constant, or
enum across the codebase.
Renaming a file that is imported by other modules (requires updating all
import paths).
Any rename where the old symbol name appears in more than one file.
Do NOT use for:
Local-only renames (a variable scoped to a single function body) — use your
editor's rename refactoring directly.
Renaming a symbol that has zero consumers — just edit the definition.
Required Tools
Tool
Purpose
repo_map (action: importers)
Find every file that imports from the target file
repo_map (action: blast_radius)
Find transitive dependents for high-risk renames
symbols
List the full exported API surface of the target file
batch_symbols
Bulk symbol extraction across multiple affected files
search
Find literal occurrences of the old symbol name across the codebase
suggest_patch
Preview changes before applying (dry-run)
apply_patch
Apply rename patches to consumer files
edit
Fallback for one-at-a-time rename edits when apply_patch is not suitable
build_check (mode: typecheck)
Verify the rename does not break compilation
test_runner
Run tests on affected files after rename
Workflow
Step 1 — Identify the target
Determine the file that exports the symbol and the symbol name to
rename.
If renaming a file itself, note the old path and the new path.
Step 2 — Discover consumers
Run repo_map with action importers and file set to the target file path.
This returns every file that imports from the target, with line numbers and
import metadata.
If the rename is high-risk (the symbol is widely used or part of a core
utility), also run repo_map with action blast_radius to understand
transitive dependents.
Step 3 — Understand the API surface
Run symbols on the target file (with exported_only: true) to see every
exported symbol. This helps confirm the exact name, signature, and whether
the symbol is re-exported.
Run batch_symbols on the consumer files identified in Step 2 to understand
how they import and use the symbol.
Step 4 — Assess impact
Read each consumer file identified in Step 2 to understand usage patterns:
Direct named imports: import { OldName } from './target'
Namespace imports: import * as ns from './target' then ns.OldName
Default imports or re-exports
Dynamic access: obj['OldName'] (see Limitations)
Count the total number of files and occurrences to gauge rename scope.
Step 5 — Execute the rename
Rename the definition in the source file first using edit.
Update each consumer file one at a time using apply_patch:
Use suggest_patch to preview the rename changes for the consumer file,
then apply the patch with apply_patch.
Replace the old symbol name with the new name in import statements.
Replace the old symbol name with the new name in usage sites within
that file.
Do NOT batch all edits into a single call — apply one file at a time so
each change is independently verifiable.
If renaming a file (not just a symbol), update all import paths in consumer
files to reflect the new file path.
If the symbol is re-exported from an index/barrel file, update the re-export
as well.
Step 6 — Dry-run verification (MANDATORY)
Before considering the rename complete:
Use suggest_patch to preview any remaining rename changes before applying
with apply_patch, ensuring the patch set is correct.
Run build_check with mode: "typecheck" and scope: "changed".
If this fails, review the output for remaining references to the old name
or type mismatches introduced by the rename.
Fix any issues found and re-run the typecheck.
Run build_check with mode: "both" if the project uses a build step
(compilation + typecheck).
Step 7 — Post-rename verification
Run test_runner with scope: "impact" or scope: "graph" on the changed
files to verify no tests break.
Run search for the old symbol name across the entire codebase to
confirm zero remaining references (excluding comments, changelogs, and
docs/releases/ history fragments).
If any references remain, determine whether they are:
Circular dependency warning: type extraction from sibling files
When consolidating types from sibling files (e.g., extracting a shared type
from evidence.ts and runner.ts into a new types.ts in the same
directory), verify import direction before creating the shared module.
If the new module imports anything from either sibling, you create a circular
dependency that silently breaks the module graph.
Example of the trap:
// types.ts — imports from a siblingimport { SomeClass } from'./runner'; // ← runner.ts will import from types.tsexportinterfaceMyType { handler: SomeClass }; // circular!
Verification steps:
Before creating the shared module, use repo_map (action: dependencies)
on each sibling file to understand what it imports.
After extraction, run repo_map (action: importers) on the new shared
module to verify it has no import edges pointing back to the siblings.
Run build_check (mode: typecheck) to confirm no circular dependency
errors.
If a circular dependency is detected, move the shared type to a module that
neither sibling imports from (e.g., a new _types.ts that has no imports
from the directory).
Why this matters: During PR #1702, consolidating types from sibling files
in src/turbo/lean/ created a circular dependency between evidence.ts,
runner.ts, and the extracted types module. The typecheck caught it, but the
fix required restructuring the extraction.
Limitations
This workflow has the following known gaps:
No alias resolution
repo_map importers and search find imports by file path, but they do not
resolve renamed imports:
import { X as Y } from'./target'; // Y is an alias for X
If you rename X to Z, the search will not find the Y alias. You must
manually check for aliased imports by searching for { X as patterns.
No type-awareness (structural typing)
This workflow is text-based, not AST-based. In TypeScript, structural typing means
a variable typed as { name: string } satisfies any interface with that shape,
regardless of the interface name. Renaming the interface name does not require
updating these structural usages, but the workflow may flag them as "missed
references" in Step 7.
Dynamic references
References via string literals, reflection, or computed property access are
invisible to static search:
If the renamed symbol is accessed dynamically anywhere, those references will
not be found by search or repo_map. Use grep for the string form of the old
name to catch these cases.
Re-exports and barrel files
If a symbol is re-exported through an index file (export { X } from './X'),
the re-export line and all downstream consumers of the re-export must also be
updated. The repo_map blast_radius action helps here, but you must manually
verify re-export chains.
Non-code references
The old symbol name may appear in:
Configuration files (JSON, YAML, TOML)
CLI argument parsers
Stringified identifiers in database records
External API contracts or documentation
These are outside the scope of this workflow but should be considered for
high-impact renames.
Checklist
Before marking a rename complete, verify every item:
Definition renamed in source file
All import statements updated across consumers
All usage sites updated across consumers
Re-exports updated (if applicable)
Import paths updated (if renaming a file)
build_check typecheck passes with no errors
Tests pass for all affected files
search for old name returns zero stale code references
Limitations reviewed and exceptions documented (if any)