Challenges over-engineering and identifies unnecessary complexity before implementation. Use when planning features, designing architecture, choosing frameworks, evaluating patterns, or when complexity, overengineering, simpler alternatives, `--complexity-analysis`, or `--keep-it-simple` are mentioned. Helps teams avoid technical debt by validating that complexity is justified.
This skill inherits all available tools. When active, it can use any tool Claude has access to.
examples/custom-auth.mdexamples/redux-overkill.mdreferences/decision-framework.mdSystematic pushback against over-engineering → justified simplicity.
<when_to_use>
NOT for: trivial tasks, clear requirements with validated complexity, regulatory/compliance-mandated approaches </when_to_use>
<phases> Track with TodoWrite when applying framework to non-trivial proposals:| Phase | Trigger | activeForm |
|---|---|---|
| Identify | Complexity smell detected | "Identifying complexity smell" |
| Alternative | Generating simpler options | "Proposing simpler alternatives" |
| Question | Probing constraints | "Questioning constraints" |
| Document | Recording decision | "Documenting decision" |
TodoWrite format:
- Identify { complexity type } smell
- Propose alternatives to { specific approach }
- Question { constraint/requirement }
- Document { decision/rationale }
Workflow:
in_progress when smell detectedcompleted, add next in_progress◇ Alternative (Minor complexity):
"Interesting approach. Help me understand why X over the more common Y?"
◆ Caution (Moderate risk):
"This pattern often leads to [specific problems]. Are we solving for something I'm not seeing?"
◆◆ Hazard (High risk):
<triggers> Common complexity smells to watch for:"This violates [principle] and will likely cause [specific issues]. I strongly recommend [alternative]. If we must proceed, we need to document the reasoning."
</escalation>
Build vs Buy: Custom solution when proven libraries exist
Indirect Solutions: Solving problem A by first solving problems B, C, D
Premature Abstraction: Layers "for flexibility" without concrete future requirements
Performance Theater: Optimizing without measurements or clear bottlenecks
Security Shortcuts: Disabling security features instead of configuring properly
CORS: * → Configure specific originsany types for external data → Runtime validation with ZodFramework Overkill: Heavy frameworks for simple tasks
Custom Infrastructure: Building platform features that cloud providers offer
<red_flags> Watch for these justifications — reframe with specific questions:
"We might need it later" → "What specific requirement do we have now?"
"It's more flexible" → "What flexibility do we need that the simple approach doesn't provide?"
"It's best practice" → "Best practice for what context? Does that context match ours?"
"It's faster" → "Have you measured? What's the performance requirement?"
"Everyone does it this way" → "For problems of this scale? Do they have our constraints?"
"It's more enterprise-ready" → "What enterprise requirement are we meeting?"
"I read about it on Hacker News" → "Does their problem match ours?" </red_flags>
<patterns> Guide toward simpler alternatives with concrete examples:Feature Flags over Plugin Architecture
// Complex
interface Plugin { transform(data: Data): Data }
const plugins = loadPlugins()
let result = data
for (const plugin of plugins) { result = plugin.transform(result) }
// Simple
const features = getFeatureFlags()
let result = data
if (features.transformA) { result = transformA(result) }
if (features.transformB) { result = transformB(result) }
Direct over Generic
// Complex (premature abstraction)
interface DataStore<T> { get(id: string): Promise<T> }
class PostgresStore<T> implements DataStore<T> { /* ... */ }
const users = new PostgresStore<User>({ /* config */ })
// Simple (direct, refactor later if needed)
async function getUser(id: string): Promise<User> {
return await db.query('SELECT * FROM users WHERE id = $1', [id])
}
Standard Library over Framework
// Complex
import _ from 'lodash'
const unique = _.uniq(array)
const mapped = _.map(array, fn)
// Simple
const unique = [...new Set(array)]
const mapped = array.map(fn)
Composition over Configuration
// Complex
const pipeline = new Pipeline({
steps: [
{ type: 'validate', rules: [...] },
{ type: 'transform', fn: 'normalize' },
{ type: 'save', destination: 'db' }
]
})
// Simple
const result = pipe(
data,
validate,
normalize,
save
)
</patterns>
<justified>
Complexity is appropriate when:
Even then:
Scan proposal for common triggers:
Always provide concrete, specific alternatives with examples:
❌ Vague: "Maybe use something simpler?" ✅ Specific: "Use Zod for validation instead of building a custom validation engine. Here's how..."
Include:
Ask probing questions to uncover hidden requirements:
If complexity chosen after validation:
NEVER: