Agent Skills: Refactor

Safe codebase refactoring with characterization tests, incremental changes, and continuous verification. Automatically activates when users want to refactor code, extract methods/classes, simplify logic, reduce duplication, improve naming, restructure modules, or clean up technical debt.

UncategorizedID: mgiovani/cc-arsenal/refactor

Install this agent skill to your local

pnpm dlx add-skill https://github.com/mgiovani/cc-arsenal/tree/HEAD/skills/refactor

Skill Files

Browse the full folder contents for refactor.

Download Skill

Loading file tree…

skills/refactor/SKILL.md

Skill Metadata

Name
refactor
Description
"Safe codebase refactoring with characterization tests, incremental changes, and continuous verification. Automatically activates when users want to refactor code, extract methods/classes, simplify logic, reduce duplication, improve naming, restructure modules, or clean up technical debt."

Refactor

Refactor code safely using characterization tests, incremental changes, and continuous verification. Every change preserves existing behavior while improving code structure, readability, and maintainability.

Refactoring Goal

$ARGUMENTS

Core Principle: Behavior Preservation

CRITICAL: Refactoring changes code structure WITHOUT changing behavior. Every step must be verified against existing tests. If tests break, the refactoring introduced a bug — revert and retry.

Anti-Hallucination Guidelines

  1. Read before changing — Never refactor code that has not been read and understood. Understand all callers and dependencies first.
  2. Test before and after — Run the full test suite before starting. Run it again after every incremental change. The results must match.
  3. Characterization tests first — If test coverage is insufficient for the target code, write characterization tests that capture current behavior BEFORE refactoring.
  4. Incremental changes — Make one small, verifiable change at a time. Never combine multiple refactoring steps into a single edit.
  5. No feature changes — Do not add features, fix bugs, or change behavior during refactoring. These are separate tasks.
  6. Reference real code — Never make claims about code structure that has not been verified by reading the actual files.

Quality Gates

This skill includes automatic refactoring verification before completion:

Safety Verification (Stop Hook)

When attempting to stop working, an automated verification agent runs to ensure the refactoring is safe:

Verification Steps:

  1. Behavior preserved: Full test suite passes (same results as before refactoring)
  2. No regressions: Linter and type checker report no new errors
  3. Characterization tests: Any tests added to capture behavior still pass
  4. Clean diff: Only intentional structural changes exist

Behavior:

  • All verifications pass: Refactoring marked complete
  • Any test fails: Completion blocked, Claude reverts or fixes the breaking change
  • ⚠️ New lint/type errors: Completion blocked until resolved

Example blocked completion:

⚠️ Refactoring verification failed:

Tests: ❌ FAILED (2 tests failing)
  - test_calculate_total: Expected 150.0, got 150
  - test_format_output: AssertionError: output format changed

Lint: ✅ PASSED
Type Check: ✅ PASSED

🔧 Refactoring introduced behavior changes. Revert the last change and retry
with a smaller step.

Task Management

This skill uses Claude Code's Task Management System for strict sequential dependency tracking through the refactoring workflow.

When to Use Tasks:

  • Multi-step refactoring across files or modules
  • Extract method/class operations requiring dependency analysis
  • Large-scale restructuring with many callers
  • Work requiring progress tracking across sessions

When to Skip Tasks:

  • Simple rename (single variable/function)
  • Trivial formatting or style fix
  • Single-line simplification

Task Structure: Refactoring creates a strict sequential chain where each phase must complete before the next can start, ensuring characterization tests exist before any structural changes begin.

Implementation Workflow

Task tracking replaces TodoWrite. Create task chain at start, update as completing each phase.

Phase 0: Project Discovery (REQUIRED)

Step 0.1: Create Task Dependency Chain

Before refactoring, create the strict sequential task structure:

TaskCreate:
  subject: "Phase 0: Discover project workflow"
  description: "Identify test, lint, type-check commands from CLAUDE.md and task runners"
  activeForm: "Discovering project workflow"

TaskCreate:
  subject: "Phase 1: Analyze refactoring scope"
  description: "Map dependencies, callers, and test coverage for target code"
  activeForm: "Analyzing refactoring scope"

TaskCreate:
  subject: "Phase 2: Write characterization tests"
  description: "Ensure sufficient test coverage before making structural changes"
  activeForm: "Writing characterization tests"

TaskCreate:
  subject: "Phase 3: Incremental refactoring"
  description: "Apply refactoring in small verified steps"
  activeForm: "Refactoring incrementally"

TaskCreate:
  subject: "Phase 4: Final verification"
  description: "Run full test suite, lint, type-check — confirm behavior preserved"
  activeForm: "Verifying refactoring safety"

TaskCreate:
  subject: "Phase 5: Final commit"
  description: "Create conventional commit with refactoring summary"
  activeForm: "Creating final commit"

# Set up strict sequential chain
TaskUpdate: { taskId: "2", addBlockedBy: ["1"] }
TaskUpdate: { taskId: "3", addBlockedBy: ["2"] }
TaskUpdate: { taskId: "4", addBlockedBy: ["3"] }
TaskUpdate: { taskId: "5", addBlockedBy: ["4"] }
TaskUpdate: { taskId: "6", addBlockedBy: ["5"] }

# Start first task
TaskUpdate: { taskId: "1", status: "in_progress" }

Step 0.2: Discover Project Workflow

Use Haiku-powered Explore agent for token-efficient discovery:

Use Task tool with Explore agent:
- prompt: "Discover the development workflow for this project:
    1. Read CLAUDE.md if it exists - extract testing and quality conventions
    2. Check for task runners: Makefile, justfile, package.json scripts, pyproject.toml scripts
    3. Identify the test command (e.g., make test, just test, npm test, pytest, bun test)
    4. Identify how to run a single test file or specific test
    5. Identify the lint command (e.g., make lint, npm run lint, ruff check)
    6. Identify the type-check command if applicable (e.g., pyright, tsc, mypy)
    7. Note any pre-commit hooks or quality gates
    8. Check for code coverage tooling (e.g., pytest --cov, nyc, c8)
    Return a structured summary of all available commands."
- subagent_type: "Explore"
- model: "haiku"  # Token-efficient for discovery

Store discovered commands for use in later phases.

Step 0.3: Run Baseline Tests

CRITICAL: Run the full test suite BEFORE making any changes. Record the results as the baseline. Every subsequent test run must match or exceed this baseline.

# Run full test suite and record results
[DISCOVERED_TEST_COMMAND]

If tests already fail before refactoring, document the pre-existing failures. These are not caused by the refactoring and should remain unchanged (same tests fail with same errors).

Step 0.4: Complete Phase 0

TaskUpdate: { taskId: "1", status: "completed" }
TaskList  # Check that Task 2 is now unblocked

Phase 1: Scope Analysis

Goal: Understand the full impact of the refactoring before touching any code.

Step 1.1: Start Phase 1

TaskUpdate: { taskId: "2", status: "in_progress" }

Step 1.2: Parallel Scope Analysis

Spawn two Explore agents in parallel to map the refactoring scope:

Agent 1 - Dependency & Caller Analysis (Explore, Haiku):
  prompt: "Analyze dependencies and callers for the refactoring target:

    Refactoring target: [DESCRIBE TARGET CODE]

    1. Read the target code — understand its current structure and public API
    2. Find ALL callers and dependents using Grep:
       - Direct function/method calls
       - Import statements referencing the target
       - Type references (if applicable)
       - Configuration or dependency injection references
    3. Map the dependency graph:
       - What does the target depend on?
       - What depends on the target?
       - Are there circular dependencies?
    4. Identify the public API surface:
       - Which functions/methods/classes are called externally?
       - Which are internal-only (safe to change freely)?
    5. Note any dynamic references (string-based lookups, reflection, decorators)

    Return:
    - Complete caller list with file:line references
    - Dependency graph (what depends on what)
    - Public vs internal API surface
    - Risks: dynamic references, external consumers, serialization"
  subagent_type: "Explore"
  model: "haiku"

Agent 2 - Test Coverage Analysis (Explore, Haiku):
  prompt: "Analyze test coverage for the refactoring target:

    Refactoring target: [DESCRIBE TARGET CODE]

    1. Find ALL test files that test the target code:
       - Unit tests directly testing target functions/classes
       - Integration tests exercising the target indirectly
       - E2E tests that flow through the target
    2. For each test, note:
       - What specific behavior it verifies
       - Which code paths it exercises
       - Which inputs and edge cases it covers
    3. Identify GAPS in test coverage:
       - Functions/methods with no tests
       - Code branches not exercised (error paths, edge cases)
       - Public API methods without direct test coverage
    4. Check for test patterns:
       - Test fixtures and helpers available
       - Mocking patterns used in the project
       - Test naming conventions

    Return:
    - List of test files with what they cover
    - Coverage gaps requiring characterization tests
    - Test patterns and fixtures available for reuse
    - Risk areas: untested code paths that refactoring could break"
  subagent_type: "Explore"
  model: "haiku"

Step 1.3: Synthesize Analysis

After both agents complete, synthesize findings:

  1. Identify which parts of the target are safe to refactor (well-tested, internal-only)
  2. Identify which parts are risky (untested, public API, dynamic references)
  3. Determine if characterization tests are needed (Phase 2)
  4. Plan the order of incremental changes

Step 1.4: Get Approval for Large Refactorings

If the refactoring involves: changes to >5 files, modifications to public APIs, moving code between modules, or changes affecting external consumers, use AskUserQuestion to present the scope analysis and get approval before proceeding.

Step 1.5: Complete Phase 1

TaskUpdate: { taskId: "2", status: "completed" }
TaskList  # Check that Task 3 is now unblocked

Phase 2: Characterization Tests

Goal: Ensure sufficient test coverage exists to detect any behavioral change from the refactoring.

Step 2.1: Start Phase 2

TaskUpdate: { taskId: "3", status: "in_progress" }

Step 2.2: Assess Coverage Needs

Based on Phase 1 coverage analysis, determine which characterization tests are needed:

  • Well-tested code (>80% path coverage): Skip to Phase 3
  • Partially tested (some gaps): Add targeted characterization tests for untested paths
  • Poorly tested (major gaps): Add comprehensive characterization tests before proceeding

Step 2.3: Write Characterization Tests

For each coverage gap identified:

  1. Read the target code to understand current behavior (including edge cases)
  2. Write tests that capture current behavior exactly:
    • Test the function/method with representative inputs
    • Test edge cases (null, empty, boundary values)
    • Test error paths (invalid inputs, failure modes)
    • Test return values AND side effects
  3. Run the characterization tests — they must ALL pass against the current (pre-refactoring) code
  4. Name tests clearly: Use prefix test_char_ or equivalent to distinguish characterization tests from behavioral tests
Example characterization test (Python):
  def test_char_calculate_total_with_discount():
      """Characterization: captures current discount calculation behavior."""
      result = calculate_total(items=[100, 200], discount=0.1)
      assert result == 270.0  # Current behavior: discount applied to sum

  def test_char_calculate_total_empty_items():
      """Characterization: captures current behavior with empty input."""
      result = calculate_total(items=[], discount=0.1)
      assert result == 0.0

IMPORTANT: Characterization tests document CURRENT behavior, not desired behavior. If the current code has a quirk, the test captures that quirk. The refactoring must preserve it.

Step 2.4: Verify Characterization Tests

Run the full test suite (including new characterization tests). All must pass.

[DISCOVERED_TEST_COMMAND]

Step 2.5: Complete Phase 2

TaskUpdate: { taskId: "3", status: "completed" }
TaskList  # Check that Task 4 is now unblocked

Phase 3: Incremental Refactoring

Goal: Apply the refactoring in small, verified steps. Each step must pass all tests.

Step 3.1: Start Phase 3

TaskUpdate: { taskId: "4", status: "in_progress" }

Step 3.2: Plan Incremental Steps

Break the refactoring into the smallest possible independent steps. Each step should be:

  • Self-contained: Makes sense on its own
  • Verifiable: Tests can confirm behavior is preserved
  • Reversible: Easy to revert if something breaks

Common refactoring step sequences (see references/patterns.md for details):

| Refactoring Type | Step Sequence | |---|---| | Extract method | 1. Create new method with copied code → 2. Test → 3. Replace original with call → 4. Test | | Extract class | 1. Create class with methods → 2. Test → 3. Delegate from original → 4. Test → 5. Update callers → 6. Test | | Rename | 1. Add new name alongside old → 2. Test → 3. Update callers → 4. Test → 5. Remove old name → 6. Test | | Move function | 1. Copy to destination → 2. Test → 3. Re-export from source → 4. Update callers → 5. Test → 6. Remove source → 7. Test | | Simplify conditional | 1. Extract condition to named variable/method → 2. Test → 3. Simplify logic → 4. Test | | Remove duplication | 1. Identify shared pattern → 2. Extract shared code → 3. Test → 4. Replace first usage → 5. Test → 6. Replace next usage → 7. Test |

Step 3.3: Execute Each Step

For EACH incremental step:

  1. Make the change — one small structural change using Edit tool
  2. Run tests immediately — using discovered test command
    [DISCOVERED_TEST_COMMAND]
    
  3. If tests pass — proceed to next step
  4. If tests fail — STOP. Analyze the failure:
    • Is it a behavioral change? → Revert and find a smaller step
    • Is it a test that needs updating? → Only if the test was testing implementation details (not behavior)
    • Is it a pre-existing failure? → Compare with baseline from Phase 0

CRITICAL: Never skip the test run between steps. Never batch multiple steps before testing. The discipline of test-after-every-change is what makes refactoring safe.

Step 3.4: Handle Complex Refactorings

For refactorings spanning multiple files:

  1. Update the target first — make the structural change in the primary file
  2. Update callers one at a time — change each caller individually, testing after each
  3. Clean up — remove old code, update imports, testing after each removal

For refactorings requiring temporary duplication:

  1. Create the new structure alongside the old
  2. Test — both old and new should work
  3. Migrate callers one at a time to the new structure, testing after each
  4. Remove the old structure once all callers are migrated
  5. Final test — full suite

Step 3.5: Complete Phase 3

TaskUpdate: { taskId: "4", status: "completed" }
TaskList  # Check that Task 5 is now unblocked

Phase 4: Final Verification

Step 4.1: Start Phase 4

TaskUpdate: { taskId: "5", status: "in_progress" }

Step 4.2: Run All Quality Checks

Run all quality checks using discovered commands from Phase 0.

Quality Gates Checklist:

  • [ ] Full test suite passes (matches or exceeds Phase 0 baseline)
  • [ ] Characterization tests pass (behavior preserved)
  • [ ] No new linting errors introduced
  • [ ] No new type errors (if typed language)
  • [ ] Code is cleaner/simpler than before (the purpose of refactoring)
  • [ ] No accidental behavior changes
  • [ ] No debug code, commented-out code, or TODO comments left behind
  • [ ] All callers updated (no dangling references)

If any check fails: Fix the issue before proceeding. Do not commit broken code. Keep task as in_progress until all gates pass.

Step 4.3: Review the Diff

Read the complete diff to verify only intentional changes exist:

git diff

Look for:

  • Unintended behavioral changes
  • Leftover debug statements
  • Unnecessary whitespace or formatting changes
  • Missing import updates
  • Orphaned code that should have been removed

Step 4.4: Complete Phase 4

TaskUpdate: { taskId: "5", status: "completed" }
TaskList  # Check that Task 6 is now unblocked

Phase 5: Final Commit

Step 5.1: Start Phase 5

TaskUpdate: { taskId: "6", status: "in_progress" }

Step 5.2: Create Commit

If /cc-arsenal:git:commit skill is available, use it. Otherwise, create a conventional commit manually:

git add [files modified]
git commit -m "refactor: [concise description of structural change]

- [What was restructured and why]
- [Key technique used: extract method, rename, simplify, etc.]
- [Impact: files changed, callers updated]

No behavioral changes."

Commit message guidelines for refactoring:

  • Type: refactor: (always — this is a structural change, not a fix or feature)
  • Subject: Describe WHAT was restructured
  • Body: Explain WHY this improves the codebase
  • Footer: Always include "No behavioral changes." to signal safety

Step 5.3: Complete Phase 5 and Refactoring

TaskUpdate: { taskId: "6", status: "completed" }
TaskList  # Show final status - all tasks should be completed

Phase 6: Summary Report

Report to the user with:

  • Refactoring performed: What structural changes were made
  • Technique used: Extract method, rename, simplify, move, etc.
  • Files modified: List with brief description of changes
  • Behavior verification: Test results before and after (matching)
  • Characterization tests added: List of new tests if any
  • Code quality improvements: Metrics if available (reduced duplication, fewer lines, better naming)
  • Commit info: Commit hash and message

Additional Resources

For detailed refactoring patterns, step sequences, and safety practices, see:

Important Notes

  • Always run Phase 0 first: Never assume which tools are available
  • Tests before and after every change: This is non-negotiable
  • Characterization tests for untested code: Never refactor code without test coverage
  • One step at a time: Never combine multiple refactoring operations
  • No behavior changes: Refactoring changes structure only — if tests break, revert
  • Ask when unsure: Better to clarify scope than to over-refactor
  • Minimal scope: Refactor only what was requested — resist the urge to "improve" adjacent code
  • Document the change: Clear commit message explaining what and why