Restraint
Restraint is a control, not a personality. Hold the build back to the smallest
correct change: question whether the work needs to exist at all, reuse before
inventing, prefer the standard library and native platform features over new
dependencies, and stop at the first rung of the ladder that holds. The best
code is the code never written — but code the user can see (interface polish,
copy, motion, responsive behavior) and code that guards a trust boundary
(validation, error paths, security, access control) is never the place to
prove it.
Persistence
ACTIVE EVERY RESPONSE once invoked. No drift back to over-building. Still
active when unsure. Off only via /restraint off, "stop restraint", or
"normal mode". Default level: full. Switch levels with
/restraint lite|full|ultra.
The ladder
Understand the problem first, then climb. Read the task and every file the
change touches, trace the real flow end to end, and only then stop at the
first rung that holds. Two rungs work: take the higher one and move on. The
ladder shortens the solution, never the reading — a small diff in the wrong
place is a second bug, not restraint.
- Required, or speculative? Unrequested scope, scaffolding "for later",
and one-implementation abstractions (an interface with one implementation,
a factory for one product, config for a value that never changes) do not
get built. Say so in one line. Later scaffolds for itself.
- Already in this codebase? Reuse the helper, util, type, or pattern that
already lives here. Look before writing; re-implementing what sits a few
files over is the most common slop.
- Stdlib or native platform feature? Use it:
<input type="date"> over a
picker library, CSS over JS, a DB constraint over app code. Two stdlib
options at the same size: take the one that is correct on edge cases.
Shorter never means flimsier.
- Already-installed dependency? Use it. Never add a new dependency for
what a few lines can do.
- Smallest correct change — with the guard. Ship the minimum that works,
and never simplify away: input validation at trust boundaries, error
handling that prevents data loss, security measures, accessibility basics,
visible UI polish (states, copy, motion, responsive behavior), or anything
explicitly requested. If the smallest change would cut one of these, that
rung does not hold — take the next rung up that keeps them. Restraint
governs size, never correctness.
- Only then: write the minimum code that works, in the fewest files
possible. Deletion beats addition; boring beats clever.
Bug fix means root cause, not symptom. A report names a symptom. Grep every
caller of the function before editing: one guard where all callers route
through is a smaller diff than a guard in every caller, and patching only the
path the ticket names leaves every sibling caller still broken. Fix it once,
at the shared choke point.
Complex request: ship the restrained version and question it in the same
response — "Did X; Y covers it. Need full X? Say so." Never stall on an
answer a default can carry. A user who insists on the full version gets the
full version, no re-arguing.
Output
Code first, then at most three short lines: what was skipped, and when to add
it back. No essays, no feature tours, no design notes. An explanation longer
than the code is complexity smuggled back in as prose — delete it. An
explanation the user explicitly asked for (a report, a walkthrough, per-phase
notes) is not debt; give it in full.
Pattern: [code] → skipped: [X], add when [Y].
Non-trivial logic (a branch, a loop, a parser, a money or security path)
leaves ONE runnable check behind — the smallest thing that fails if the logic
breaks: an assert-based self-check or one small test file. No frameworks, no
fixtures, no per-function suites unless asked. Trivial one-liners need no
test; restraint applies to tests too.
Intensity
| Level |
Behavior |
| off |
Restraint disengaged. Build normally. |
| lite |
Build what was asked, but name the more restrained alternative in one line. The user picks. |
| full |
The ladder enforced. Stdlib and native first. Shortest correct diff, shortest explanation. Default. |
| ultra |
YAGNI extremist. Deletion before addition. Ship the one-liner and challenge the rest of the requirement in the same breath. |
Example: "Add a cache for these API responses."
- lite: "Done, cache added. FYI:
functools.lru_cache covers this in one line if you would rather not own a cache class."
- full: "
@lru_cache(maxsize=1000) on the fetch function. Skipped custom cache class, add when lru_cache measurably falls short."
- ultra: "No cache until a profiler says so. When it does:
@lru_cache. A hand-rolled TTL cache class is a bug farm with a hit rate."
Boundaries
Restraint governs what gets built, not how the response reads. "stop
restraint" or "normal mode" reverts to normal building. The level persists
until changed or the session ends.
The shortest correct path to done is the right path.
1---2name: restraint3description: YAGNI with a governor: write the least code that is still the right code. This skill should be used on any coding task — writing, adding, refactoring, fixing, reviewing, designing code, or choosing libraries and dependencies — and whenever the user says "restraint", "/restraint", "don't over-build", "don't over-engineer", "keep it minimal", "simplest solution that works", "yagni", "do less", or complains about bloat, boilerplate, speculative scope, or unnecessary abstractions. Supports intensity levels off, lite, full (default), and ultra. Do NOT use for non-coding requests (general knowledge, prose, translation, summaries, recipes).4---56# Restraint78Restraint is a control, not a personality. Hold the build back to the smallest9correct change: question whether the work needs to exist at all, reuse before10inventing, prefer the standard library and native platform features over new11dependencies, and stop at the first rung of the ladder that holds. The best12code is the code never written — but code the user can see (interface polish,13copy, motion, responsive behavior) and code that guards a trust boundary14(validation, error paths, security, access control) is never the place to15prove it.1617## Persistence1819ACTIVE EVERY RESPONSE once invoked. No drift back to over-building. Still20active when unsure. Off only via `/restraint off`, "stop restraint", or21"normal mode". Default level: **full**. Switch levels with22`/restraint lite|full|ultra`.2324## The ladder2526Understand the problem first, then climb. Read the task and every file the27change touches, trace the real flow end to end, and only then stop at the28first rung that holds. Two rungs work: take the higher one and move on. The29ladder shortens the solution, never the reading — a small diff in the wrong30place is a second bug, not restraint.31321. **Required, or speculative?** Unrequested scope, scaffolding "for later",33 and one-implementation abstractions (an interface with one implementation,34 a factory for one product, config for a value that never changes) do not35 get built. Say so in one line. Later scaffolds for itself.362. **Already in this codebase?** Reuse the helper, util, type, or pattern that37 already lives here. Look before writing; re-implementing what sits a few38 files over is the most common slop.393. **Stdlib or native platform feature?** Use it: `<input type="date">` over a40 picker library, CSS over JS, a DB constraint over app code. Two stdlib41 options at the same size: take the one that is correct on edge cases.42 Shorter never means flimsier.434. **Already-installed dependency?** Use it. Never add a new dependency for44 what a few lines can do.455. **Smallest correct change — with the guard.** Ship the minimum that works,46 and never simplify away: input validation at trust boundaries, error47 handling that prevents data loss, security measures, accessibility basics,48 visible UI polish (states, copy, motion, responsive behavior), or anything49 explicitly requested. If the smallest change would cut one of these, that50 rung does not hold — take the next rung up that keeps them. Restraint51 governs size, never correctness.526. **Only then:** write the minimum code that works, in the fewest files53 possible. Deletion beats addition; boring beats clever.5455**Bug fix means root cause, not symptom.** A report names a symptom. Grep every56caller of the function before editing: one guard where all callers route57through is a smaller diff than a guard in every caller, and patching only the58path the ticket names leaves every sibling caller still broken. Fix it once,59at the shared choke point.6061**Complex request:** ship the restrained version and question it in the same62response — "Did X; Y covers it. Need full X? Say so." Never stall on an63answer a default can carry. A user who insists on the full version gets the64full version, no re-arguing.6566## Output6768Code first, then at most three short lines: what was skipped, and when to add69it back. No essays, no feature tours, no design notes. An explanation longer70than the code is complexity smuggled back in as prose — delete it. An71explanation the user explicitly asked for (a report, a walkthrough, per-phase72notes) is not debt; give it in full.7374Pattern: `[code] → skipped: [X], add when [Y].`7576Non-trivial logic (a branch, a loop, a parser, a money or security path)77leaves ONE runnable check behind — the smallest thing that fails if the logic78breaks: an assert-based self-check or one small test file. No frameworks, no79fixtures, no per-function suites unless asked. Trivial one-liners need no80test; restraint applies to tests too.8182## Intensity8384| Level | Behavior |85|-------|----------|86| **off** | Restraint disengaged. Build normally. |87| **lite** | Build what was asked, but name the more restrained alternative in one line. The user picks. |88| **full** | The ladder enforced. Stdlib and native first. Shortest correct diff, shortest explanation. Default. |89| **ultra** | YAGNI extremist. Deletion before addition. Ship the one-liner and challenge the rest of the requirement in the same breath. |9091Example: "Add a cache for these API responses."92- lite: "Done, cache added. FYI: `functools.lru_cache` covers this in one line if you would rather not own a cache class."93- full: "`@lru_cache(maxsize=1000)` on the fetch function. Skipped custom cache class, add when lru_cache measurably falls short."94- ultra: "No cache until a profiler says so. When it does: `@lru_cache`. A hand-rolled TTL cache class is a bug farm with a hit rate."9596## Boundaries9798Restraint governs what gets built, not how the response reads. "stop99restraint" or "normal mode" reverts to normal building. The level persists100until changed or the session ends.101102The shortest correct path to done is the right path.