Agent skill
refactor
Clean up implementation code while keeping tests green. Improve code quality without changing behaviour. Use after implement phase to polish code before review.
Install this agent skill to your Project
npx add-skill https://github.com/sofer/.agents/tree/main/skills/refactor
SKILL.md
Refactor
Improve code structure and quality while keeping all tests passing. This completes the TDD red-green-refactor cycle.
Purpose
Refactoring improves code without changing behaviour:
- Improve readability and maintainability
- Remove duplication
- Simplify complexity
- Align with project standards
- Prepare code for review
Input
Expect from orchestrator:
- Implementation files from implement phase
- Passing test suite
- Project standards (patterns, naming, style)
- Design document (for architectural alignment)
Golden rule
Tests must stay green throughout refactoring.
After every change, run tests. If tests fail, the change altered behaviour - revert and try a different approach.
Process
1. Ensure green baseline
Verify all tests pass before starting:
npm test
# ✓ All tests passing
2. Identify refactoring opportunities
Review code for:
Code smells:
- Long methods (>20 lines)
- Deep nesting (>3 levels)
- Duplicate code
- Large classes
- Long parameter lists
- Feature envy (method uses another class more than its own)
- Data clumps (groups of data that appear together)
Standards alignment:
- Naming conventions
- Code style
- Pattern adherence
- Error handling consistency
3. Apply refactoring techniques
Extract method
// Before
async createUser(input: CreateUserInput): Promise<User> {
const email = input.email.toLowerCase().trim();
if (!email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
throw new ValidationError('Invalid email');
}
// ... more code
}
// After
async createUser(input: CreateUserInput): Promise<User> {
const email = this.normaliseEmail(input.email);
this.validateEmail(email);
// ... more code
}
private normaliseEmail(email: string): string {
return email.toLowerCase().trim();
}
private validateEmail(email: string): void {
if (!email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
throw new ValidationError('Invalid email');
}
}
Extract constant
// Before
if (name.length > 100) { ... }
// After
const MAX_NAME_LENGTH = 100;
if (name.length > MAX_NAME_LENGTH) { ... }
Rename for clarity
// Before
const d = new Date();
const u = await repo.save(data);
// After
const createdAt = new Date();
const savedUser = await userRepository.save(userData);
Simplify conditionals
// Before
if (user !== null && user !== undefined) {
if (user.active === true) {
return user;
}
}
return null;
// After
if (user?.active) {
return user;
}
return null;
Remove duplication
// Before (in multiple methods)
const email = input.email.toLowerCase().trim();
// After (extracted to shared method)
const email = this.normaliseEmail(input.email);
Introduce parameter object
// Before
function createUser(email: string, name: string, role: string, department: string)
// After
function createUser(input: CreateUserInput)
4. Refactor in small steps
- Make one small change
- Run tests
- If green, commit mentally (or actually)
- If red, revert immediately
- Repeat
5. Run tests continuously
# Watch mode for instant feedback
npm test -- --watch
6. Final verification
After all refactoring:
- All tests still pass
- Code coverage unchanged or improved
- No new linting errors
- Code compiles without warnings
Refactoring checklist
Readability
- Variable names are descriptive
- Method names describe what they do
- Comments explain why, not what
- No magic numbers or strings
Structure
- Methods are focused (single responsibility)
- Classes are cohesive
- No deep nesting
- Clear control flow
Duplication
- No copy-pasted code
- Common logic extracted
- Consistent patterns used
Standards
- Naming follows conventions
- Code style matches project
- Error handling is consistent
- Logging follows patterns
Output
refactor:
story_id: "US-001"
changes:
- type: "extract_method"
description: "Extracted email normalisation to separate method"
files: ["src/services/user.service.ts"]
rationale: "Reused in multiple places, improves readability"
- type: "rename"
description: "Renamed 'u' to 'savedUser' for clarity"
files: ["src/services/user.service.ts"]
rationale: "Improves code readability"
- type: "extract_constant"
description: "Extracted MAX_EMAIL_LENGTH constant"
files: ["src/services/user.service.ts", "src/types/constants.ts"]
rationale: "Removes magic number, centralises configuration"
- type: "simplify"
description: "Simplified null check using optional chaining"
files: ["src/repositories/user.repository.ts"]
rationale: "Modern syntax, more readable"
run_result:
command: "npm test"
total: 12
passed: 12
failed: 0
status: "green" # Required - unchanged from implement
decisions:
- decision: "Kept validation in service layer"
rationale: "Consistent with existing pattern; controller stays thin"
notes: "Minor refactoring only; implementation was already clean"
Update manifest:
stories:
US-001:
phase: "refactor"
decisions:
- phase: "refactor"
decision: "Extracted email normalisation"
rationale: "DRY principle, used in 3 places"
Gate
Must pass before proceeding to code-review:
- All tests still pass (100%)
- No decrease in test coverage
- Code compiles without warnings
- Linting passes
What NOT to do
- Don't add new features (that requires tests first)
- Don't change public interfaces without updating tests
- Don't refactor untested code (add tests first)
- Don't make multiple changes before testing
- Don't over-engineer or gold-plate
Tips
- Small steps are safer than big leaps
- If a refactoring is hard, maybe the code needs tests first
- Trust the tests; if they pass, behaviour is preserved
- Refactoring is optional if code is already clean
- Time-box refactoring to avoid perfectionism
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
meeting-context
Determine why a meeting is happening and what should be discussed
reconcile
Analyse and resolve divergences between SDLC manifest and actual development state (git commits, branches, uncommitted files). Use when manifest and reality have drifted apart, or before picking next story to ensure clean state.
readme-review
Review the project README to understand what it does and suggest a recommended next step. Use when starting work on an unfamiliar project.
init-override
Create a symlink from AGENTS.md to CLAUDE.md in the current project directory. Use when the user wants to initialise a project to use AGENTS.md as the memory file instead of CLAUDE.md.
commit
Git workflow operations with Conventional Commits. Supports subcommands - branch (create feature branch), commit (stage and commit changes), pr (create pull request), merge (merge PR). Automatically available when the current directory is a git repository. Use when user needs git operations during development workflow.
contact-research
Research a person given their name and email, returning a brief profile with role, company, LinkedIn summary, and previous interactions
Didn't find tool you were looking for?