/refactor — Behavior-Preserving Code Refactor
Plan + execute + verify a refactor that changes structure without changing behavior. RALF loop on the test suite ensures behavior equivalence.
When to use
- Breaking up large functions / classes
- Migrating to new patterns (class → functional, raw SQL → ORM)
- Extracting to a shared library
- Improving testability (dependency injection, pure functions)
Not for
- Adding features →
/develop
- Fixing bugs →
/bugfix
- Schema/library/version migrations →
/migrate
Invocation
/refactor --files "src/api/*.ts" --goal "extract auth middleware to shared lib"
/refactor --files "src/components/**/*.tsx" --goal "convert class-based to functional components"
/refactor --files "src/data/*.py" --goal "introduce Repository pattern" --preserve-tests
Arguments
| Flag |
Default |
Effect |
--files <glob> |
ask user |
Glob pattern or file list |
--goal '<text>' |
required |
Plain-English goal of refactor |
--preserve-tests |
true |
Keep existing tests passing throughout |
Output
- Refactored code in assigned files
- Test suite passing (tests updated only if signatures genuinely change)
<repo>/.ai-skills-memory/refactor/<run-id>/REFACTOR-LOG.md — before/after comparison + rationale
- Pull request with diff + refactor log
Agent roster
| Agent |
Model |
Effort |
Tools |
Role |
team-lead (resolves to feature-design-lead) |
Opus |
high |
Task |
Plans refactor steps; assigns per file; verifies no behavior change |
developer (per-stack) |
inherit |
high |
Read, Write, Edit, Bash |
Executes refactor per assigned file(s) |
qa-engineer |
inherit |
medium |
Bash, Read |
Verifies behavior equivalence (full test suite) |
Pipeline
┌─ PLAN:
│ └─ Lead reads target files, scopes refactor, breaks into per-file steps
│ Generates REFACTOR-PLAN.md with before/after sketches
│
│ Prerequisite checks:
│ • Coverage scan on target files. If line coverage <80%
│ → developer writes characterization tests as a SEPARATE PRIOR PHASE
│ per `references/characterization-tests.md` BEFORE refactor begins.
│ • If refactor crosses >5 files OR module/package boundaries
│ → use Mikado method per `references/mikado-method.md`;
│ emit MIKADO.md alongside REFACTOR-PLAN.md.
│ • REFACTOR-PLAN.md MUST list named refactorings per file using
│ canonical names from `references/fowler-catalogue.md`
│ (e.g. "Extract Function", "Replace Conditional with Polymorphism").
│
├─ Gate: user approval of plan
│
├─ EXECUTE (sequential per file per `subagent-isolation.md` Sequential Code-Modification Gate):
│ └─ developer: refactor assigned file(s)
│ After each file: run tests via /run-tests
│ If tests fail: diagnose, refactor until tests pass
│
├─ Gate: all files refactored, all tests passing
│
├─ RALF (test validation loop):
│ │ Oracle: cli:./run-tests.sh (or detected test command)
│ │ Kill-on: same-error-repeats:2
│ │ Caps: 4 iter / 200K tokens / 45 min
│ │ On fail: developer revises refactor; re-run tests
│ └─ (loop back to test run)
│
└─ Lead verifies no behavior change:
- API diff check (public surface unchanged unless explicitly in goal)
- Test coverage preserved
Memory write: L4 refactor decision + rationale
PR description: generated from REFACTOR-PLAN
G7 spawn payloads
All spawns use structured G7 payloads per plugin/schemas/spawn-payload.schema.json. Lead validates returns against plugin/schemas/return-contract.schema.json.
Eval rubric
Pointer: plugin/eval/judge-rubrics/refactor.md (B10).
Dimensions:
- Behavior equivalence — all existing tests pass; no breaking changes to public API
- Code improvement — readability, maintainability, or performance demonstrably improved
- Scope correctness — refactor stays within stated goal; no unrelated changes
- Test coverage preserved — test suite still exercises the code at same coverage
- Documentation updated — docstrings, comments, README reflect changes
Pass: avg ≥ 4.0, no dimension < 3.
RALF wiring
- Oracle:
cli:./run-tests.sh (or auto-detected per project test command)
- Kill-on:
same-error-repeats:2 (two iterations with same error → likely a real behavior change, not a refactor bug)
- Caps: 4 iter / 200K tokens / 45 min — overridable in userConfig
Memory writes
| Layer |
When |
Shape |
| L4 |
After plan approval |
.ai-skills-memory/refactor/<run-id>/plan.md |
| L4 |
After completion |
.ai-skills-memory/refactor/<run-id>/final.md — before/after stats (lines, complexity metrics) |
Failure modes
- Refactor scope creeps: Lead stops work; user must clarify goal
- Tests fail after refactor: developer re-examines; if persistent (kill-on triggers), this likely indicates behavior change masquerading as refactor — escalate to user
--preserve-tests violated: lead refuses to advance to next file; rolls back the offending change
Observability events
workflow_start — refactor + goal
plan_generated — per-file plan
ralf_iter — test validation iterations
workflow_end — PR_OPENED or ESCALATED
Integration
- Orchestrator:
feature-design-lead (the only agent with tools: Task)
- Schemas:
plugin/schemas/spawn-payload.schema.json, plugin/schemas/return-contract.schema.json
- Sub-workflows:
/run-tests (test execution + auto-fix per failure)
- Companions:
/ralph (RALF loop), /context-load (per-role context), /subagent-spawn (G7 payload assembly), /create-pr (PR after completion)
- Rules:
subagent-isolation (Sequential Code-Modification Gate per file), ralph-budget (caps), untrusted-content-wrapping (G1 wrap on tool outputs + subagent returns), memory-discipline (REFACTOR-LOG.md → L4)
- Hooks:
tool-output-normalize.py (G2 on test runner stdout)
1---2name: refactor3description: Use this skill when breaking up large functions, migrating to new patterns, extracting to a library, or improving testability — to plan and execute a code refactor that changes structure without changing behavior via a multi-agent pipeline with a mandatory test-equivalence gate enforced by RALF. Not for adding features (use /develop) or fixing bugs (use /bugfix).4context: fork5argument-hint: "[--files <glob>] --goal '<plain-english goal>' [--preserve-tests]"6---78# /refactor — Behavior-Preserving Code Refactor910Plan + execute + verify a refactor that changes structure without changing behavior. RALF loop on the test suite ensures behavior equivalence.1112## When to use1314- Breaking up large functions / classes15- Migrating to new patterns (class → functional, raw SQL → ORM)16- Extracting to a shared library17- Improving testability (dependency injection, pure functions)1819## Not for2021- Adding features → `/develop`22- Fixing bugs → `/bugfix`23- Schema/library/version migrations → `/migrate`2425## Invocation2627```28/refactor --files "src/api/*.ts" --goal "extract auth middleware to shared lib"29/refactor --files "src/components/**/*.tsx" --goal "convert class-based to functional components"30/refactor --files "src/data/*.py" --goal "introduce Repository pattern" --preserve-tests31```3233## Arguments3435| Flag | Default | Effect |36|---|---|---|37| `--files <glob>` | ask user | Glob pattern or file list |38| `--goal '<text>'` | required | Plain-English goal of refactor |39| `--preserve-tests` | true | Keep existing tests passing throughout |4041## Output4243- Refactored code in assigned files44- Test suite passing (tests updated only if signatures genuinely change)45- `<repo>/.ai-skills-memory/refactor/<run-id>/REFACTOR-LOG.md` — before/after comparison + rationale46- Pull request with diff + refactor log4748## Agent roster4950| Agent | Model | Effort | Tools | Role |51|---|---|---|---|---|52| `team-lead` (resolves to `feature-design-lead`) | Opus | high | Task | Plans refactor steps; assigns per file; verifies no behavior change |53| `developer` (per-stack) | inherit | high | Read, Write, Edit, Bash | Executes refactor per assigned file(s) |54| `qa-engineer` | inherit | medium | Bash, Read | Verifies behavior equivalence (full test suite) |5556## Pipeline5758```59┌─ PLAN:60│ └─ Lead reads target files, scopes refactor, breaks into per-file steps61│ Generates REFACTOR-PLAN.md with before/after sketches62│63│ Prerequisite checks:64│ • Coverage scan on target files. If line coverage <80%65│ → developer writes characterization tests as a SEPARATE PRIOR PHASE66│ per `references/characterization-tests.md` BEFORE refactor begins.67│ • If refactor crosses >5 files OR module/package boundaries68│ → use Mikado method per `references/mikado-method.md`;69│ emit MIKADO.md alongside REFACTOR-PLAN.md.70│ • REFACTOR-PLAN.md MUST list named refactorings per file using71│ canonical names from `references/fowler-catalogue.md`72│ (e.g. "Extract Function", "Replace Conditional with Polymorphism").73│74├─ Gate: user approval of plan75│76├─ EXECUTE (sequential per file per `subagent-isolation.md` Sequential Code-Modification Gate):77│ └─ developer: refactor assigned file(s)78│ After each file: run tests via /run-tests79│ If tests fail: diagnose, refactor until tests pass80│81├─ Gate: all files refactored, all tests passing82│83├─ RALF (test validation loop):84│ │ Oracle: cli:./run-tests.sh (or detected test command)85│ │ Kill-on: same-error-repeats:286│ │ Caps: 4 iter / 200K tokens / 45 min87│ │ On fail: developer revises refactor; re-run tests88│ └─ (loop back to test run)89│90└─ Lead verifies no behavior change:91 - API diff check (public surface unchanged unless explicitly in goal)92 - Test coverage preserved93 Memory write: L4 refactor decision + rationale94 PR description: generated from REFACTOR-PLAN95```9697## G7 spawn payloads9899All spawns use structured G7 payloads per `plugin/schemas/spawn-payload.schema.json`. Lead validates returns against `plugin/schemas/return-contract.schema.json`.100101## Eval rubric102103Pointer: `plugin/eval/judge-rubrics/refactor.md` (B10).104105Dimensions:1061. **Behavior equivalence** — all existing tests pass; no breaking changes to public API1072. **Code improvement** — readability, maintainability, or performance demonstrably improved1083. **Scope correctness** — refactor stays within stated goal; no unrelated changes1094. **Test coverage preserved** — test suite still exercises the code at same coverage1105. **Documentation updated** — docstrings, comments, README reflect changes111112Pass: avg ≥ 4.0, no dimension < 3.113114## RALF wiring115116- **Oracle:** `cli:./run-tests.sh` (or auto-detected per project test command)117- **Kill-on:** `same-error-repeats:2` (two iterations with same error → likely a real behavior change, not a refactor bug)118- **Caps:** 4 iter / 200K tokens / 45 min — overridable in userConfig119120## Memory writes121122| Layer | When | Shape |123|---|---|---|124| L4 | After plan approval | `.ai-skills-memory/refactor/<run-id>/plan.md` |125| L4 | After completion | `.ai-skills-memory/refactor/<run-id>/final.md` — before/after stats (lines, complexity metrics) |126127## Failure modes128129- **Refactor scope creeps:** Lead stops work; user must clarify goal130- **Tests fail after refactor:** developer re-examines; if persistent (kill-on triggers), this likely indicates behavior change masquerading as refactor — escalate to user131- **`--preserve-tests` violated:** lead refuses to advance to next file; rolls back the offending change132133## Observability events134135- `workflow_start` — refactor + goal136- `plan_generated` — per-file plan137- `ralf_iter` — test validation iterations138- `workflow_end` — `PR_OPENED` or `ESCALATED`139140## Integration141142- **Orchestrator**: `feature-design-lead` (the only agent with `tools: Task`)143- **Schemas**: `plugin/schemas/spawn-payload.schema.json`, `plugin/schemas/return-contract.schema.json`144- **Sub-workflows**: `/run-tests` (test execution + auto-fix per failure)145- **Companions**: `/ralph` (RALF loop), `/context-load` (per-role context), `/subagent-spawn` (G7 payload assembly), `/create-pr` (PR after completion)146- **Rules**: `subagent-isolation` (Sequential Code-Modification Gate per file), `ralph-budget` (caps), `untrusted-content-wrapping` (G1 wrap on tool outputs + subagent returns), `memory-discipline` (REFACTOR-LOG.md → L4)147- **Hooks**: `tool-output-normalize.py` (G2 on test runner stdout)