simplify-code
Analyze code for complexity and suggest simplifications. Detects verbose patterns, redundant logic, and opportunities for cleaner code.
Usage
/simplify-code
Analyzes recent changes or discussed files by default. You can also specify:
- A file path to analyze a specific file
- A directory to analyze all source files in it
--applyto apply safe, mechanical transformations (use with caution)
Instructions
Step 1: Discover Project Context
Use the Explore agent (via Task tool with subagent_type="Explore") to discover project context:
Explore Prompt:
Discover project context for simplifying code. Find and read:
- Root CLAUDE.md - Read
CLAUDE.mdat project root. All instructions are MANDATORY.- Relevant CLAUDE.md Files - Search
**/CLAUDE.mdfor keywords: conventions, style, patterns, complexity, simplification- Project Type - Detect from package.json, pyproject.toml, go.mod, Cargo.toml, etc.
Return: Project language, coding conventions, complexity guidelines
From the Explore results, extract:
- Project type and language
- Coding conventions and patterns
- Any simplification guidelines from CLAUDE.md
If Explore returns no context, proceed with language-agnostic analysis using general best practices.
Step 2: Identify Target Code
Determine what to analyze based on context:
If specific files provided:
- Analyze the provided files
If current context has recent changes:
# Get recently modified files
git diff --name-only HEAD~5
# Or unstaged changes
git diff --name-only
If no specific target:
- Identify source directories:
src/,lib/,app/, or language-specific conventions - Use Glob to find source files:
**/*.ts,**/*.py, etc. based on project type - Exclude patterns:
**/node_modules/**,**/vendor/**,**/*.test.*,**/*.spec.*,**/dist/**,**/build/** - Skip test files, generated files, lock files
Step 3: Analyze for Complexity Issues
Scan the code for these patterns:
Structural Issues
| Issue | Threshold | Example |
|---|---|---|
| Deep nesting | > 3 levels | Nested if/for/while |
| Long functions | > 30 lines | Functions doing too much |
| Many parameters | > 4 params | Functions with long signatures |
| Long files | > 300 lines | Files doing too much |
| Complex conditionals | > 3 conditions | if (a && b || c && d) |
Redundant Code
| Pattern | Simplification |
|---|---|
if (x) return true else return false |
return x |
if (x) return true; return false |
return x |
if (x == true) |
if (x) |
if (x == false) |
if (!x) |
if (x != null && x != undefined) |
if (x != null) or optional chaining |
| Dead code after return | Remove unreachable code |
| Unused variables | Remove or use |
| Duplicate code blocks | Extract to function |
Verbose Patterns
| Verbose | Simplified |
|---|---|
| Manual loops for transformation | map/filter/reduce |
| Manual null checks | Optional chaining |
| String concatenation | Template literals |
| Callback nesting | async/await |
| Multiple assignments | Destructuring |
AI-Generated Code Smells
| Smell | Issue |
|---|---|
| Overly verbose variable names | theResultOfTheCalculation -> result |
| Excessive inline comments | Comments stating the obvious |
| Boilerplate wrapper functions | Single-use wrappers |
| Over-abstraction | Premature abstraction for one use case |
| Unnecessary type annotations | Types that can be inferred |
Step 4: Language-Specific Simplifications
JavaScript/TypeScript
// Verbose
if (value !== null && value !== undefined) {
result = value.property;
}
// Simplified
result = value?.property;
// Verbose
const x = value !== null && value !== undefined ? value : defaultValue;
// Simplified
const x = value ?? defaultValue;
// Verbose
const obj = { name: name, age: age };
// Simplified
const obj = { name, age };
// Verbose
function getData() {
return fetch(url).then(res => res.json()).then(data => process(data));
}
// Simplified
async function getData() {
const res = await fetch(url);
const data = await res.json();
return process(data);
}
Python
# Verbose
result = []
for item in items:
if item.active:
result.append(item.name)
# Simplified
result = [item.name for item in items if item.active]
# Verbose
name = "Hello " + first_name + " " + last_name
# Simplified
name = f"Hello {first_name} {last_name}"
# Verbose
if value is not None:
result = value
else:
result = default
# Simplified
result = value if value is not None else default
# Or with walrus operator (Python 3.8+)
if (result := get_value()) is not None:
process(result)
# Verbose
file = open("data.txt")
try:
data = file.read()
finally:
file.close()
# Simplified
with open("data.txt") as file:
data = file.read()
Go
// Verbose
var result string
result = getValue()
// Simplified
result := getValue()
// Verbose
if err != nil {
return fmt.Errorf("failed: %v", err)
}
// Simplified (Go 1.13+)
if err != nil {
return fmt.Errorf("failed: %w", err)
}
// Verbose
func process() (result int, err error) {
result = 0
err = nil
// ...
return result, err
}
// Simplified with named returns
func process() (result int, err error) {
// ...
return
}
Rust
// Verbose
match result {
Ok(value) => value,
Err(e) => return Err(e),
}
// Simplified
result?
// Verbose
match optional {
Some(value) => do_something(value),
None => {},
}
// Simplified
if let Some(value) = optional {
do_something(value);
}
// Verbose
let mut result = Vec::new();
for item in items {
result.push(item.transform());
}
// Simplified
let result: Vec<_> = items.iter().map(|item| item.transform()).collect();
Java
// Verbose
List<String> names = new ArrayList<>();
for (User user : users) {
names.add(user.getName());
}
// Simplified
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
// Verbose
String result;
if (value != null) {
result = value;
} else {
result = "default";
}
// Simplified
String result = Optional.ofNullable(value).orElse("default");
// Verbose
public class Point {
private final int x;
private final int y;
public Point(int x, int y) { this.x = x; this.y = y; }
// getters, equals, hashCode, toString...
}
// Simplified (Java 16+)
public record Point(int x, int y) {}
C#
// Verbose
string result;
if (value != null) {
result = value.ToUpper();
} else {
result = null;
}
// Simplified
string result = value?.ToUpper();
// Verbose
List<string> names = new List<string>();
foreach (var user in users) {
names.Add(user.Name);
}
// Simplified
var names = users.Select(u => u.Name).ToList();
// Verbose
if (obj is MyClass) {
var typed = (MyClass)obj;
typed.DoSomething();
}
// Simplified
if (obj is MyClass typed) {
typed.DoSomething();
}
Step 5: Prioritize Findings
Categorize issues by:
Impact (High to Low):
- Bug risks (dead code, unreachable code)
- Maintainability (complex functions, deep nesting)
- Readability (verbose patterns)
- Style (minor improvements)
Risk (for applying changes):
- Safe: Mechanical transformations (redundant boolean, obvious simplifications)
- Moderate: Restructuring (extracting functions, changing loops)
- High: Architectural changes (require understanding of business logic)
Step 6: Generate Report
Output findings in this format (see below).
Step 7 (Final): Evaluate Reusable Patterns
Run the pattern-evaluator agent to assess whether any reusable patterns (rules, skills, or agents) were discovered during this session and should be persisted.
Report Format
Output findings in this format:
## Code Simplification Report
**Files Analyzed**: [count]
**Issues Found**: [count]
**Estimated Reduction**: [X lines / Y% reduction possible]
---
## Critical (Bug Risks)
### [Issue Title]
**File**: [path:line]
**Issue**: [description]
**Risk**: [Safe / Moderate / High]
**Before:**
```[language]
[original code]
After:
[simplified code]
Technique: [name of simplification technique]
Warnings (Maintainability)
[Issue Title]
File: [path:line] Issue: [description] Risk: [Safe / Moderate / High]
Before:
[original code]
After:
[simplified code]
Suggestions (Readability)
[Issue Title]
File: [path:line]
Before:
[original code]
After:
[simplified code]
Summary
| Metric | Before | After (if applied) |
|---|---|---|
| Total Lines | X | Y |
| Avg Function Length | X | Y |
| Max Nesting Depth | X | Y |
| Complex Conditionals | X | Y |
Safe to Apply
These changes are mechanical and safe to apply automatically:
- [Change 1] ([file:line])
- [Change 2] ([file:line])
Run /simplify-code --apply to apply safe changes.
Requires Review
These changes need human review before applying:
- [Change 1] - [why it needs review]
- [Change 2] - [why it needs review]
Recommendations
- [High-impact recommendation]
- [Medium-impact recommendation]
- [Optional improvement]
Next Steps:
- Run tests after applying any changes
- Review moderate/high risk changes manually
- Consider refactoring [specific area] in a separate PR
---
## Safety Rules
### Default Mode (Suggest Only)
- Analyze and report findings
- Show before/after comparisons
- Do not modify any files
### Apply Mode (--apply)
Only apply changes that are:
- Mechanical transformations
- Safe (no behavior change possible)
- Examples: redundant boolean simplification, obvious null coalescing
**Never auto-apply:**
- Function extraction/reorganization
- Architectural changes
- Anything requiring business logic understanding
- Changes in complex conditional logic
### Always Recommend
- Run tests after any changes
- Review changes before committing
- Consider impact on team/codebase conventions
---
---
## Scope Limits
**Maximum files per run:**
- If the target contains more than 50 files, prioritize recently modified files (if git available)
- Limit initial analysis to 20 files
- Report: "Analyzed X of Y files. Run with specific paths for complete analysis."
---
## Error Handling
### No Files Found
If no analyzable files are found:
Question: "No source files found in the specified location. What should I do?" Options:
- Specify file paths explicitly
- Check a different directory
- Cancel
### Git Not Available
If git commands fail (not a git repo):
- Fall back to analyzing all source files in the provided path
- Skip the "recent changes" detection
- Note in report: "Git not available - analyzed all source files"
### File Read Errors
If some files cannot be read:
- Log the file path and error
- Continue with remaining files
- Include in report: "X files could not be analyzed due to access errors"
### Analysis Timeout
If analysis exceeds 5 minutes:
- Output partial results
- Note: "Analysis incomplete - processed X of Y files"
### Apply Mode Failures
If a safe transformation fails when using `--apply`:
- Skip and continue to next file
- Report all failures at the end
- Never leave files in a partially-modified state
---
## Tips
- Focus on high-impact, low-risk improvements first
- Respect project conventions (from detect-context)
- Don't over-simplify at the cost of readability
- Consider team familiarity with advanced language features
- One simplification per issue for clarity