Overview
Safe, verified patterns for renaming identifiers across hundreds of files in a monorepo. Tested on STRATT (39 files, ~2,000 identifiers, 0 regressions). Core principle: Dry-run verification → count validation → execution → post-execution verification. Tools:rg (ripgrep), sed, git (for safety).
Pattern 1: Simple Identifier Rename (95% of cases)
Scenario: Rename a type name, function name, or config key across multiple files. Example:SkillRef → DoctrineRef
Step 1: Dry-Run Count
Step 2: Dry-Run Preview
Step 3: Execute with sed (File-by-File)
Option A: Using ripgrep + xargs + sedrg "SkillRef" packages/ -l— list files containing “SkillRef”xargs sed -i 's/SkillRef/DoctrineRef/g'— apply sed to each file-i— in-place edit (modifies files)s/old/new/g— sed substitute (global in file)
Step 4: Verify Count Matches
git checkout, debug, try again.
Step 5: Type Check + Test
Step 6: Commit
Pattern 2: Regex-Based Replacement (Complex Identifiers)
Scenario: Rename with context or multiple variations. Example: Renameexport interface Skill { → export interface Doctrine { (only for specific pattern, not all “Skill” occurrences)
Step 1: Build Regex Pattern
Step 2: Execute with sed Regex
.= any char,\{= literal{(escaped for safety)s/pattern/replacement/g= substitute all occurrences in line
Step 3: Verify
Pattern 3: Multi-Step Replacement (Chained Identifiers)
Scenario: One name change leads to multiple derived changes. Example: RenameSkillRef → DoctrineRef AND skill_ref → doctrine_ref (snake_case variant)
Strategy: Replace in Dependency Order
- If you replace
skill_reffirst, you might accidentally hitSkillRef→DoctrineRefpartials - Always replace most-specific (SkillRef) before less-specific (skill_ref)
Pattern 4: File Extension Rename (Hard-Cut)
Scenario: Rename file extensions, e.g.,.skill.md → .doctrine.md
Step 1: Find All
Step 2: Rename All
Step 3: Update File References in Code
Step 4: Commit (File + Code Changes in Same Commit)
Pattern 5: Exclude-Based Replacement (Comments, Strings, Docs)
Scenario: Replace in code only, NOT in comments or docs. Example: RenameSkill → Doctrine in TypeScript, but leave // Skill-based... comments alone
Challenge
sed doesn’t easily distinguish code from comments. Use a smarter approach:
Safer Approach: Manual Review + Commit Per File
Pattern 6: Config Key Rename (YAML/JSON)
Scenario: Rename a config key, but support both old + new during transition. Example: Renameskills: → doctrines: in council.yaml, but keep old key working
Step 1: Add Fallback in Code
Step 2: Gradually Update Configs (Optional)
Step 3: Remove Fallback Later
Once all configs migrated:Safety Checklist
Before executing any bulk replacement:- Record pre-execution count with
rg --count-matches - Preview with
rg "pattern" | head -20 - Use dry-run (show files with
-lbefore applying sed) - Test on 1–2 files manually before xargs
- Never use
sed -iwithout a backup (use git) - After execution, verify count with
rg "new_name" --count-matches - Run tests + type check
- Review
git difffor unintended changes - Commit with clear message showing what changed
Common Pitfalls
❌ Usingsed -i without git
- One typo = data loss
- Always work in git repo; use
git checkoutto revert
.matches any char,*means repeat- Use
\.for literal dot,\{for literal brace - Test on small files first
sed 's/Skill/Doctrine/g'hits all files- Use
rg --files-with-matches -l | xargs sedto scope correctly
- “I think it worked” ≠ verified
- Always run the count check
- If things break, hard to debug
- Separate: file extension first (commit 1), then identifiers (commit 2)
Command Reference Card
Scaling Examples
Example 1: Small Rename (50 occurrences, 5 files)
Example 2: Medium Rename (500 occurrences, 20 files, multi-variant)
Example 3: Large Rename with File Extension (2,000 occurrences, 39 files)
Related Artifacts
- Operational pattern: devarno-cloud/atlas/campaigns/2026-04-03-mechanical-refactor-workflow.md
- STRATT implementation: stratt-hq (commits 1–7, bulk replacements executed in each)
- Ripgrep docs: https://github.com/BurntSushi/ripgrep