Agent skill
code-migration
Use when moving logic between layers, deprecating patterns, refactoring responsibilities, or enforcing canonical owners. Ensures migrations are complete with no legacy coexistence.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/code-migration
SKILL.md
Code Migration
Core principle: When you move responsibility from A to B, delete A.
Half-migrations are technical debt. If files_helper.py and path_comp.py both construct paths, every developer must learn which one to use. That ambiguity is the bug.
Migration Checklist
When moving logic from one location to another:
- Move the code to its canonical location
- Update all call sites (use grep, not hope)
- Update skills that reference the old location
- Add ruff rules to ban imports from the old location
- Delete the old code (not deprecate - delete)
- Run validate_skills.py to catch stale references
- Run tests to confirm nothing broke
If you can't check all boxes, the migration isn't done.
Canonical Owners
Every responsibility has exactly ONE canonical owner:
| Responsibility | Canonical Owner | NOT |
|---|---|---|
| Library path construction | path_comp.py |
files_helper.py |
| Wall-clock timestamps | time_helper.now_ms() |
time.time() |
| Monotonic intervals | time_helper.internal_ms() |
time.monotonic() |
| Essentia calls | ml_backend_essentia_comp.py |
anywhere else |
| Logging setup | logging_helper.get_logger() |
logging.getLogger() |
| Config access | Injected AppConfig |
os.environ, config.yaml |
If two places can do the same thing, one of them is wrong.
Enforcement Stack
Migrations are enforced at every layer:
1. Ruff Rules (Syntax-Level)
Ban dangerous imports before code runs:
# ruff.toml
[lint.flake8-tidy-imports.banned-api]
"time.time".msg = "Use nomarr.helpers.time_helper.now_ms() for timestamps"
"builtins.print".msg = "Use logging via get_logger()"
2. Import-Linter (Architecture-Level)
Prevent layer violations:
helpers cannot import from services
workflows cannot import from interfaces
only ml_backend_essentia_comp.py may import essentia
3. Skills (Documentation-Level)
Every skill documents what IS canonical, not what WAS.
4. validate_skills.py (Tooling-Level)
Catches stale references in skills:
python scripts/validate_skills.py --check-refs
Anti-Patterns
Deprecation Warnings
# ❌ Wrong - deprecation is procrastination
import warnings
warnings.warn("Use path_comp instead", DeprecationWarning)
If it's deprecated, delete it. Pre-alpha means no backwards compatibility.
Keeping It Around Just In Case
# ❌ Wrong - dead code that looks alive
def old_path_builder(path: str) -> str:
"""DEPRECATED: Use path_comp.build_library_path_from_input()"""
...
Delete it. Git remembers.
TODO: Remove After Migration
# ❌ Wrong - TODOs are lies
# TODO: Remove this once all callers use the new API
def legacy_function():
...
Remove it now. The migration isn't done until it's gone.
Wrapper For Compatibility
# ❌ Wrong - shims become permanent
def get_path(path: str) -> str:
"""Compatibility wrapper."""
return path_comp.build_library_path_from_input(path).absolute
Update the callers directly.
Migration Workflow
Step 1: Identify the Migration
# Find all usages of the old pattern
python scripts/discover_import_chains.py nomarr.helpers.files_helper
# Or grep for specific functions
grep -r "build_path" nomarr/
Step 2: Create the Canonical Location
Move the logic to its proper layer (components for business logic, helpers for pure utilities).
Step 3: Update All Call Sites
# Find all files that import the old module
grep -r "from nomarr.helpers.files_helper import" nomarr/
Step 4: Ban the Old Pattern (If Still Exists)
If old code still exists and has callers, add a temporary ruff ban to prevent new usages:
# Add to ruff.toml during migration
[lint.flake8-tidy-imports.banned-api]
"nomarr.helpers.files_helper.build_path".msg = "Use path_comp.build_library_path_from_input()"
Remove the ban after deleting the old code. Bans for deleted patterns are garbage.
Step 5: Delete the Old Code
git rm nomarr/helpers/old_module.py
Step 6: Update Skills
python scripts/validate_skills.py --check-refs
Step 7: Verify Migration Complete
# Check that all traces are gone
python scripts/check_migration.py nomarr.helpers.old_module
# If migration plan included a ruff ban, verify it exists
python scripts/check_migration.py nomarr.helpers.old_module --expect-ban
# Full QC
python scripts/run_qc.py
pytest
Decision Framework
When you find duplicate responsibilities:
Q: Is there a clear canonical owner?
├─ No → Decide which location should own it
└─ Yes → Q: Does the old location still exist?
├─ Yes → Delete it. Update callers first if needed.
└─ No → Good. Verify skills and rules match reality.
When someone proposes keeping both:
"Can we keep the old one for compatibility?"
→ No. Pre-alpha. Delete it.
"What if something still uses it?"
→ Find it and update it. That's the migration.
"What if we need it later?"
→ Git remembers. Delete it.
Validation
Before considering a migration complete, run:
python scripts/check_migration.py nomarr.old.pattern
The script validates:
- Old code is deleted, not deprecated
- No imports of the old module remain
- No skill references to old pattern
- No
# TODO: removecomments remain - (With
--expect-ban) Ruff ban exists
Manual checks:
- No wrapper/shim functions exist
- Tests pass
The migration is done when there's no trace of the old pattern.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?