Stop over-engineering
The best code is the code you never wrote. This skill is one rule applied
relentlessly: before adding anything, find what can leave.
Inspired by Ponytail by Dietrich
Gebert (MIT). This is an independent, company-agnostic reimplementation of the
same idea — go star the original.
The core insight
Over-engineering scales with ambiguity. When a task is vague, the model
hedges: it builds scaffolding for unknowns it's imagining — config it might
need, an interface for the second caller that doesn't exist, a flag nobody will
flip. So this stance is an ambiguity rebate: it pays off exactly in
proportion to how underspecified the task is.
- Vague/large task → strip the invented scaffolding. This is where you win big.
- Tight/small task → there's nothing to strip. Don't add ceremony; just do the small thing. The real fix for a clear task is a clearer spec, not a persona.
What to hunt for (delete-list)
When writing or reviewing, look specifically for:
- Reinvented standard library — a hand-rolled helper for something the
language/runtime already does. Delete it, use the builtin.
- Unneeded dependencies — a whole package pulled in for one trivial call.
Inline the few lines or drop it.
- Speculative abstractions — interfaces, base classes, plugin systems, and
"managers" with exactly one implementation. Collapse to the concrete case.
Add the seam when the second case actually arrives, not before.
- Dead flexibility — config options, feature flags, and parameters that
are never varied; branches no input reaches. Remove the knob.
- Premature layers — wrappers around wrappers, indirection that only
forwards. Cut the middle.
How to apply
- Start from subtraction. First question on any change: "what can I remove
or not add and still be correct?"
- Match effort to the task. Don't bring a framework to a one-liner.
- Prefer what's already here — the standard library and existing patterns in
the repo before a new dependency or a new pattern.
- Ship the boring version. Clear beats clever; the smallest correct thing wins.
- Name the bloat plainly when you flag it — "this abstraction has one caller",
"this flag is never set" — so the cut is obvious, not a matter of taste.
What this is NOT
- Not "write less code at all costs" — correctness and readability come first.
Deleting a needed error path is not simplification.
- Not an excuse to skip tests, types, or handling real edge cases that do occur.
- Not a money-saver knob. On already-tight work it can cost slightly more for no
gain; its value is as a guardrail against bloat, applied where ambiguity lives.
1---2name: stop-overengineering3description: Stop over-engineering4---56# Stop over-engineering78The best code is the code you never wrote. This skill is one rule applied9relentlessly: **before adding anything, find what can leave.**1011Inspired by [Ponytail](https://github.com/DietrichGebert/ponytail) by Dietrich12Gebert (MIT). This is an independent, company-agnostic reimplementation of the13same idea — go star the original.1415## The core insight1617Over-engineering scales with **ambiguity**. When a task is vague, the model18hedges: it builds scaffolding for unknowns it's *imagining* — config it might19need, an interface for the second caller that doesn't exist, a flag nobody will20flip. So this stance is an **ambiguity rebate**: it pays off exactly in21proportion to how underspecified the task is.2223- **Vague/large task** → strip the invented scaffolding. This is where you win big.24- **Tight/small task** → there's nothing to strip. Don't add ceremony; just do the small thing. The real fix for a clear task is a clearer spec, not a persona.2526## What to hunt for (delete-list)2728When writing or reviewing, look specifically for:29301. **Reinvented standard library** — a hand-rolled helper for something the31 language/runtime already does. Delete it, use the builtin.322. **Unneeded dependencies** — a whole package pulled in for one trivial call.33 Inline the few lines or drop it.343. **Speculative abstractions** — interfaces, base classes, plugin systems, and35 "managers" with exactly one implementation. Collapse to the concrete case.36 Add the seam when the *second* case actually arrives, not before.374. **Dead flexibility** — config options, feature flags, and parameters that38 are never varied; branches no input reaches. Remove the knob.395. **Premature layers** — wrappers around wrappers, indirection that only40 forwards. Cut the middle.4142## How to apply4344- **Start from subtraction.** First question on any change: "what can I remove45 or *not* add and still be correct?"46- **Match effort to the task.** Don't bring a framework to a one-liner.47- **Prefer what's already here** — the standard library and existing patterns in48 the repo before a new dependency or a new pattern.49- **Ship the boring version.** Clear beats clever; the smallest correct thing wins.50- **Name the bloat plainly** when you flag it — "this abstraction has one caller",51 "this flag is never set" — so the cut is obvious, not a matter of taste.5253## What this is NOT5455- Not "write less code at all costs" — correctness and readability come first.56 Deleting a needed error path is not simplification.57- Not an excuse to skip tests, types, or handling real edge cases that *do* occur.58- Not a money-saver knob. On already-tight work it can cost slightly more for no59 gain; its value is as a guardrail against bloat, applied where ambiguity lives.