# Restraint

> 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).

- Skill: `b-open-io-prompts/restraint` (Agent Skill)
- Install (CLI): `npx skillmds@latest add b-open-io-prompts/restraint`
- Raw SKILL.md: https://api.skillmd.com/api/skills/b-open-io-prompts/restraint/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: b-open-io (https://skillmd.com/u/b-open-io-prompts)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/b-open-io-prompts/restraint

---


# 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.

1. **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.
2. **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.
3. **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.
4. **Already-installed dependency?** Use it. Never add a new dependency for
   what a few lines can do.
5. **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.
6. **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.

