
Radical Simplification
- 70 installs
- 191 repo stars
- Updated July 24, 2026
- pproenca/dot-skills
radical-simplification is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
Key points
- radical-simplification
- AI & Agent Building
- AI-coding skill
Radical Simplification by the numbers
- 70 all-time installs (skills.sh)
- +5 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #5,700 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pproenca/dot-skills --skill radical-simplificationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 70 |
|---|---|
| repo stars | ★ 191 |
| Last updated | July 24, 2026 |
| Repository | pproenca/dot-skills ↗ |
How do I helps with ai & agent building tasks during ai-assisted development?
Helps with ai & agent building tasks during AI-assisted development.
Who is it for?
Best when you're working on ai & agent building and need structured help with radical-simplification.
Skip if: Teams with no ai & agent building needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with ai & agent building tasks during ai-assisted development, or when radical-simplification is a claude code skill for ai & agent building. it helps solo builders move faster with ai-assisted coding.
What you get
Structured output aligned to radical-simplification: radical-simplification; AI & Agent Building; AI-coding skill.
Files
Radical Simplification — Cognitive Moves for Collapsing Complex Problems
Distillation of the documented working method of mathematicians, physicists, and engineers who consistently turn complex problems into simple solutions. The skill is not a step list — it is a toolbox of cognitive moves, each correcting a specific wrong default a capable model has when faced with complexity. The moves are mostly orthogonal; pick the one that matches the symptom.
This is the thinking layer that sits above refactoring (code-simplifier), metric design (deterministic-metric-design), and reviews (design-review). Those skills apply a methodology to a known shape of artifact. This skill is the methodology itself — how to arrive at the simple shape in the first place.
When to Apply
Use this skill when:
- The user says the problem feels too complicated, that the team is going in circles, or that there must be a simpler way
- A proposed design has accreted parameters, dependencies, or branches and feels overengineered
- A plan has been drafted but unresolved decisions remain, and the agent is about to commit to assumed answers
- A bug investigation has tried several variants of the same approach without progress
- A review surfaces complexity that may be accidental (Brooks) rather than essential
- The agent is asked to find an elegant solution to a hard engineering or product problem
- Forward search has exhausted and the agent needs a different angle (work backwards, invert, transfer from another domain)
- The agent is producing fluent-sounding output but cannot back it up under expansion (Feynman test)
This skill is not for cleaning up code that already does the right thing — that is code-simplifier. Use this when the approach itself is what needs to get simpler.
How to Use
The nine categories are orthogonal cognitive moves. Match the move to the symptom:
| Symptom | Reach for | First rule to read |
|---|---|---|
| Solving feels off — maybe the wrong problem | Frame | `frame-restate-problem` |
| Plan drafted but unresolved decisions remain | Clarify | `clarify-interview-one-at-a-time` |
| Drowning in cases, parameters, branches | Reduce | `reduce-toy-case-first` |
| Parts are tangled; changes ripple | Decompose | `decomp-orthogonal-axes` |
| Forward search is exponential or stuck | Invert | `invert-work-backwards` |
| Missing the structural truth of the system | Constrain | `constrain-name-the-invariant` |
| Stuck inside the current vocabulary | Transfer | `transfer-cross-domain-analogue` |
| The specific problem keeps resisting | Generalize | `gen-rising-sea` |
| Producing fluent output you cannot back up | Audit | `audit-feynman-technique` |
For category overviews and the ordering rationale, see `references/_sections.md`.
Rule Categories
| # | Category | Prefix | Move | Rules |
|---|---|---|---|---|
| 1 | Reframe the Problem | frame | Restate, separate essential from accidental, find the decision | 3 |
| 2 | Clarify Through Interview | clarify | One-at-a-time questions with recommended answers; read the source before asking | 2 |
| 3 | Reduce to the Smallest Case | reduce | Toy case, limit cases, Pareto compression | 3 |
| 4 | Decompose Along Orthogonal Axes | decomp | Orthogonal axes, WHAT vs HOW | 2 |
| 5 | Invert the Search | invert | Work backwards, assume failure | 2 |
| 6 | Constrain with Invariants and Symmetries | constrain | Name the invariant, dimensional check | 2 |
| 7 | Transfer From Another Domain | transfer | Cross-domain analogue, vocabulary lock-in | 2 |
| 8 | Generalize Until the Problem Dissolves | gen | Rising sea | 1 |
| 9 | Audit Your Own Understanding | audit | Feynman, name the confusion, Fermi check | 3 |
Quick Reference
1. Reframe the Problem
- `frame-restate-problem` — Restate in your own words before solving; surfaces the wrong-problem case while it is still cheap
- `frame-essential-vs-accidental` — Brooks's distinction: name each piece of complexity as inherent or layered-on
- `frame-find-decision-point` — Find the decision the answer must change; answer that, not the literal question
2. Clarify Through Interview
- `clarify-interview-one-at-a-time` — Walk the design tree one branch at a time; every question paired with your recommended answer so the user reviews a position, not generates one
- `clarify-prefer-source-over-asking` — If a grep, file read, or runtime check would answer it, do that — only ask what the source cannot tell you
3. Reduce to the Smallest Case
- `reduce-toy-case-first` — Solve n=1 fully before generalizing; the structure of the big problem becomes visible
- `reduce-limit-cases` — Probe zero, infinity, empty, identity to expose where the design degrades
- `reduce-pareto-compress` — Design for the 20% of inputs that produce 80% of the result
4. Decompose Along Orthogonal Axes
- `decomp-orthogonal-axes` — Axes are correct when changing one does not force changing another; verbs over today's nouns
- `decomp-what-vs-how` — Write the WHAT before debating the HOW; the spec is the referee
5. Invert the Search
- `invert-work-backwards` — When forward search is exponential, ask what must be true one step before the goal
- `invert-assume-failure` — Write the postmortem before writing the design (Munger's inversion)
6. Constrain with Invariants and Symmetries
- `constrain-name-the-invariant` — The property that does not change is often the answer in disguise
- `constrain-dimensional-check` — Mismatched units, types, or categories are bugs before they are runtime failures
7. Transfer From Another Domain
- `transfer-cross-domain-analogue` — Search for the structural twin in another domain; the twin's solution often transplants
- `transfer-suspect-vocabulary-lock-in` — Suffix accretion (
Manager,Helper,Coordinator) signals the original noun is wrong
8. Generalize Until the Problem Dissolves
- `gen-rising-sea` — Grothendieck's rising sea; the more abstract version is sometimes the easier one — but only if it has fewer concepts, not more
9. Audit Your Own Understanding
- `audit-feynman-technique` — Unfold technical shorthand into beginner-vocabulary sentences; the hand-waves are the gaps
- `audit-name-the-confusion` — When stuck, name what you do not know — do not retry variants of the same approach
- `audit-fermi-sanity-check` — Bound the answer order-of-magnitude before producing it; 10× disagreements are the signal
Related Skills
- `code-simplifier` — Refactoring patterns once the right approach is known (this skill ends, that one begins)
- `deterministic-metric-design` — Applies this methodology to the specific problem of inventing metrics
- `design-review` — Applies this methodology to the specific problem of reviewing UI
Authoring Note
These moves are load-bearing, not decorative. The wrong default each rule corrects is named in the rule itself — if a rule restates something a capable model already does correctly, cut it. The coverage of the skill is proven by /dev-skill:eval on real complex-problem prompts, not by hitting a rule count.
Problem-Solving Methodology
Version 0.2.0 dot-skills May 2026
---
Abstract
Methodology distillation of the documented cognitive moves used by mathematicians, physicists, and software engineers known for collapsing complex problems into simple solutions — Pólya, Feynman, Hamming, Brooks, Knuth, Dijkstra, Lamport, Tao, Grothendieck, Munger, and Hofstadter. 20 rules across 9 orthogonal categories — Reframe, Clarify, Reduce, Decompose, Invert, Constrain, Transfer, Generalize, Audit — each naming a specific wrong default a capable model has when facing complexity, the cognitive move that corrects it, and a concrete engineering example showing the move applied. The skill is the thinking layer above refactoring and review — how to arrive at a simple shape, not how to refactor toward one.
---
Table of Contents
1. Reframe the Problem
- 1.1 Find the decision the answer must change
- 1.2 Restate the problem in your own words before solving
- 1.3 Separate essential complexity from accidental complexity
2. Clarify Through Interview
- 2.1 Interview one question at a time, each with your recommended answer
- 2.2 If the codebase can answer it, read the codebase — only ask what the source cannot tell you
3. Reduce to the Smallest Case
- 3.1 Cut to the 20% that produces 80% of the result
- 3.2 Probe limit cases — zero, infinity, empty, identity
- 3.3 Solve the smallest non-trivial case fully before generalizing
4. Decompose Along Orthogonal Axes
- 4.1 Decompose along axes that do not entangle
- 4.2 Specify WHAT before implementing HOW
5. Invert the Search
- 5.1 Assume the design failed and find the most likely cause
- 5.2 Work backwards from the goal when forward search exhausts
6. Constrain with Invariants and Symmetries
- 6.1 Check dimensional, type, or category consistency
- 6.2 Name the invariant — it is usually the answer
7. Transfer From Another Domain
- 7.1 Find a structurally identical solved problem in another domain
- 7.2 Suspect the surrounding vocabulary when stuck
8. Generalize Until the Problem Dissolves
- 8.1 Generalize until the specific problem dissolves
9. Audit Your Own Understanding
- 9.1 Bound the answer with a Fermi estimate before producing it
- 9.2 Explain it as if to a beginner — gaps in explanation are gaps in understanding
- 9.3 Name what you do not understand instead of retrying variants
---
References
1. https://en.wikipedia.org/wiki/How_to_Solve_It 2. https://www.cs.virginia.edu/~robins/YouAndYourResearch.html 3. https://en.wikipedia.org/wiki/No_Silver_Bullet 4. https://dl.acm.org/doi/10.1145/356635.356640 5. https://dl.acm.org/doi/10.1145/361598.361623 6. https://dl.acm.org/doi/10.1145/363235.363259 7. https://www.microsoft.com/en-us/research/publication/state-the-problem-before-presenting-the-solution/ 8. https://en.wikipedia.org/wiki/Dimensional_analysis 9. https://en.wikipedia.org/wiki/Feynman%27s_Lost_Lecture 10. https://terrytao.wordpress.com/ 11. https://fs.blog/great-talks/a-lesson-on-elementary-worldly-wisdom/ 12. https://en.wikipedia.org/wiki/Alexander_Grothendieck#The_rising_sea_metaphor 13. https://en.wikipedia.org/wiki/The_Psychology_of_Invention_in_the_Mathematical_Field 14. https://www.basicbooks.com/titles/douglas-hofstadter/surfaces-and-essences/9780465018475/ 15. https://www.physics.umd.edu/perg/fermi/fermi.htm 16. https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/
---
Source Files
This document was compiled from individual reference files. For detailed editing or extension:
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for creating new rules |
| SKILL.md | Quick reference entry point |
| metadata.json | Version and reference URLs |
{Title — identical to the YAML title}
{1–3 sentences naming the wrong default a capable model has here, and the concrete consequence of that default. Do not write ALWAYS or NEVER — write what goes wrong.}
``{language-or-text} {One canonical example: the move applied to a concrete engineering or product problem. Use realistic names — never foo/bar/MyComponent. Show the move in action, not as a slogan. Plain-text "thought-process" examples (with the lang tag text`) are fine for cognitive moves where code would be a distraction.}
{Optional: one short paragraph naming when the move is a trap — e.g. "Generalizing
is *not* the right move when the abstract version has more concepts than the
specific one." Include only when there is a real failure mode of the move itself.}
Reference: [{Author — Title or Talk}](https://primary-source-url)
{
"name": "radical-simplification",
"version": "0.2.0",
"organization": "dot-skills",
"technology": "Problem-Solving Methodology",
"discipline": "distillation",
"type": "code-quality",
"date": "May 2026",
"abstract": "Methodology distillation of the documented cognitive moves used by mathematicians, physicists, and software engineers known for collapsing complex problems into simple solutions — Pólya, Feynman, Hamming, Brooks, Knuth, Dijkstra, Lamport, Tao, Grothendieck, Munger, and Hofstadter. 20 rules across 9 orthogonal categories — Reframe, Clarify, Reduce, Decompose, Invert, Constrain, Transfer, Generalize, Audit — each naming a specific wrong default a capable model has when facing complexity, the cognitive move that corrects it, and a concrete engineering example showing the move applied. The skill is the thinking layer above refactoring and review — how to arrive at a simple shape, not how to refactor toward one.",
"references": [
"https://en.wikipedia.org/wiki/How_to_Solve_It",
"https://www.cs.virginia.edu/~robins/YouAndYourResearch.html",
"https://en.wikipedia.org/wiki/No_Silver_Bullet",
"https://dl.acm.org/doi/10.1145/356635.356640",
"https://dl.acm.org/doi/10.1145/361598.361623",
"https://dl.acm.org/doi/10.1145/363235.363259",
"https://www.microsoft.com/en-us/research/publication/state-the-problem-before-presenting-the-solution/",
"https://en.wikipedia.org/wiki/Dimensional_analysis",
"https://en.wikipedia.org/wiki/Feynman%27s_Lost_Lecture",
"https://terrytao.wordpress.com/",
"https://fs.blog/great-talks/a-lesson-on-elementary-worldly-wisdom/",
"https://en.wikipedia.org/wiki/Alexander_Grothendieck#The_rising_sea_metaphor",
"https://en.wikipedia.org/wiki/The_Psychology_of_Invention_in_the_Mathematical_Field",
"https://www.basicbooks.com/titles/douglas-hofstadter/surfaces-and-essences/9780465018475/",
"https://www.physics.umd.edu/perg/fermi/fermi.htm",
"https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/"
]
}
Sections
This file defines the categories and their order. The prefix in parentheses is the filename prefix that groups rules. Categories are ordered by leverage — the cognitive moves most often missing when a competent agent is stuck on a complex problem go first. This is a methodology skill, not a performance one, so categories carry no fixed impact tier: the right move depends on the problem in front of you, not on a hard-coded priority.
The moves are mostly orthogonal — you do not walk them in order. Pick the one that fits the symptom: stuck → audit; over-elaborated → frame or reduce; plan-drafted-but-unresolved → clarify; forward search exhausted → invert; entangled → decomp; outside your vocabulary → transfer; specific problem resists → gen; missing structural truth → constrain.
---
1. Reframe the Problem (frame)
Description: Whether the problem the agent is solving is the problem actually being asked. The most expensive failure mode is solving the wrong problem perfectly. Covers restating before solving, distinguishing essential from accidental complexity, and finding the decision underneath the surface request.
2. Clarify Through Interview (clarify)
Description: Once a plan exists but before implementation begins, the agent must extract the decisions the user actually owns — without dumping a wall of questions and without committing to assumed answers. Covers dependency-ordered Socratic interview where every question is paired with a recommended answer, and the discipline of reading the codebase first so the user is only asked what the source cannot tell.
3. Reduce to the Smallest Case (reduce)
Description: Shrinking the problem until its structure is visible, then scaling back up. The core "simple solution" move: an answer that works on n=1, at limit cases, and across the highest-leverage 20% generalizes; one built on the full noisy general case usually does not. Covers toy models, limit-case probes, and Pareto compression.
4. Decompose Along Orthogonal Axes (decomp)
Description: Splitting the problem so the parts do not entangle. Wrong decompositions hide complexity inside the seams between parts. Covers finding axes where changing one thing does not break another, and separating WHAT (the specification) from HOW (the implementation) so each can be argued about on its own.
5. Invert the Search (invert)
Description: Looking from the other end of the problem. Forward search from the current state can be exponentially harder than backward search from the goal, and considering only success paths blinds the agent to the failure modes that determine the design. Covers working backwards from the desired outcome and Munger-style inversion (assume the solution failed — what is the most likely cause?).
6. Constrain with Invariants and Symmetries (constrain)
Description: Finding what does not change to pin down what does. The invariant is often the answer in disguise; equal inputs producing unequal outputs reveals a hidden coupling; mismatched units or types signals a category error before any code runs. Covers naming the invariant and dimensional/type consistency checks.
7. Transfer From Another Domain (transfer)
Description: Searching outside the current vocabulary for a structurally identical solved problem. Staying inside a domain's terminology silently constrains the solution space to whatever that domain has already considered. Covers cross-domain analogues and noticing when the surrounding vocabulary is the cage.
8. Generalize Until the Problem Dissolves (gen)
Description: When the specific problem resists, Grothendieck's rising sea — raise the surrounding water until what looked like a cliff is submerged. A more abstract version of the problem can be the easier one, because it exposes the structure the specific case obscures. Covers when and how to generalize as a simplification, not a complication.
9. Audit Your Own Understanding (audit)
Description: Catching the moments when the agent has stopped thinking and started pattern-matching. Stuck-and-retrying, fluent-sounding shorthand, and unbounded answers all signal an unaudited reasoning step. Covers explain-to-a-beginner (Feynman technique), naming the confusion explicitly when stuck, and Fermi-style sanity bounds before producing an answer.
Bound the answer with a Fermi estimate before producing it
Fermi's habit: before computing or measuring, estimate the answer's order of magnitude from first principles. If the eventual measurement disagrees with the estimate by more than 10×, the measurement (or the estimate) is wrong, and the disagreement is where the real problem lives. The default agent failure is to produce a number with no prior — so it has no way to notice when the number is implausible.
Question: "How many DB queries does this checkout endpoint make?"
Fermi estimate (before reading the trace, ~30 seconds of thinking):
1× session lookup
1× user row
1× cart fetch
N× cart items (or 1 if batched) → N or 1
1× payment record write
1× order row write
1× audit log write
────
~7 to (7 + items)
Trace shows: 47 queries on a 4-item cart.
The Fermi estimate said ~11. The measurement is 4× too high — and
that gap is the bug. Likely culprits: an N+1 on items, plus an
unbatched fetch of related entities. Confirmed in 2 minutes.
Without the estimate, "47 queries" looks like a number — it is only
"too many" if you had a sense of what "enough" was.The estimate does not have to be precise; an order of magnitude is enough. Apply it to: query counts, response sizes, memory usage, request rates, cache hit rates, anything where the agent is about to produce a number. If the actual differs by 10×, do not move on — the gap is the signal.
Reference: University of Maryland — Fermi Questions in physics teaching
Explain it as if to a beginner — gaps in explanation are gaps in understanding
Feynman's diagnostic: try to explain the topic to a curious beginner who knows none of the vocabulary. The places where the explanation needs a hedge ("roughly", "sort of", "for our purposes") or a hand-wave are the places the explainer does not actually understand. The default failure is fluent-sounding shorthand that looks like understanding because the words are correct; the test is whether they can be unfolded.
Agent writes: "We use eventual consistency for sessions because it
scales better."
Feynman expansion (forced, in beginner vocabulary):
"When a user logs in on phone A, we write the session to one server.
Other servers learn about it slowly — usually within 200ms but
sometimes up to 5 seconds during heavy load.
So if the user logs in on phone A and then opens the app on tablet B
within 5 seconds, tablet B might see the old logged-out state and
ask them to log in again.
We accepted this because [reason] — and the reason has to be more
than 'it scales better', because the cost is the user occasionally
sees a stale login state, which is a real UX cost."
After expanding, the agent realises:
- The 5s upper bound was a guess, not measured.
- The actual reason was 'we didn't want to run a Redis cluster',
not 'scales better' — and the alternative ('one Postgres write')
would have scaled to the actual traffic too.
The expansion turned a fluent assertion into a list of falsifiable
claims, two of which were wrong.A useful trigger: any time the agent writes "for performance", "because of scale", "for correctness", or "for reasons" — stop and unfold each into a sentence a non-expert could verify. Most of the time, two of the three claims dissolve.
Name what you do not understand instead of retrying variants
When stuck, the default is to retry variants of the same approach — change a parameter, try a different library call, swap a clause. This is the agent equivalent of pattern-matching against fluency. The move that breaks the loop is naming the confusion: write down, in a sentence, what you do not understand. The named confusion becomes a falsifiable question; the unnamed one stays a fog.
Bug: this SQL query returns 0 rows, but the row should exist.
Variant-retry loop (the trap):
Add a WHERE clause. Remove it. Change = to LIKE. Try ILIKE. Try
LOWER(). Try the row from a different ID. Check casing. Try the
staging DB. Try a DIFFERENT query that should also hit the row.
Three hours pass. No progress, because the agent never said what
it does not know.
Name the confusion (the move):
"I do not know whether:
(a) the row does not exist (the data is wrong),
(b) the WHERE clause excludes it (the filter is wrong),
(c) the JOIN drops it (a referenced row is missing),
(d) the user lacks RLS access to it (auth is wrong)."
Now there are four falsifiable hypotheses, each with a one-line test:
(a) SELECT 1 FROM t WHERE id = X
(b) SELECT * FROM t WHERE id = X (no other filters)
(c) Run the joined tables separately
(d) SELECT current_user; check RLS policies on t
One of them will be true within five minutes. The variant-retry loop
could have run all day.The mechanical trigger: if the agent has tried more than three variants of the same approach without progress, the next action is not another variant. It is "I will write down what I do not understand, then test the cheapest hypothesis."
Reference: Pólya — How to Solve It, "Looking Back" / understanding failure
Interview one question at a time, each with your recommended answer
Once a plan exists but before any code is written, the default failure is to commit to assumed answers and produce a fluent solution to a problem the user did not actually have. The opposite default — dumping a wall of seven unrelated questions — is just as bad, because it pushes the cost of thinking back onto the user and signals that the agent has no view. The move is a dependency-ordered Socratic interview: walk down the design tree one branch at a time, and for every open decision pose exactly one question paired with your recommended answer and the reasoning behind it. The user then accepts, redirects, or vetoes — and the next question depends on what they chose.
Bad: wall of questions, no recommendations.
1. What auth provider?
2. Sync or async?
3. SQL or document DB?
4. Where does the queue live?
5. Retry policy?
6. Idempotency keys?
7. ...
The user has to think from scratch on seven independent axes,
most of which depend on the answers to the others.
Good: one question, with a recommendation, in dependency order.
Q1: This flow has one upstream caller and ~50 req/s peak. I'm
recommending **synchronous, in-process** over a queue —
a queue adds at-least-once semantics you would then have
to design around, and the load doesn't justify it.
Sound right, or is there a reason to decouple I'm missing?
→ User: "Actually we'll add a second caller in Q3 that's bursty."
Q2: Given the bursty second caller in Q3, I'm now recommending
a **bounded in-memory buffer with backpressure**, NOT a
durable queue — bursty != needs-durability, and durability
reopens the at-least-once design. Does the second caller
tolerate a 503 under sustained burst, or does it need
guaranteed acceptance?
→ User: "503 is fine, they retry."
Q3: Backpressure shape — I'm recommending **token bucket at
the HTTP layer** over a worker-pool queue, because it
keeps the failure mode at the edge where the caller can
observe it. Counter-argument: a pool gives you per-tenant
isolation. Are tenants a real axis here?Three properties matter. One question at a time — sequencing exposes which decisions depend on which, so the user is not being asked to pre-commit to coupled answers. Always a recommended answer with reasoning — anchors the conversation in your model of the problem so the user is reviewing a position, not generating one. Walk the dependency tree, not a flat checklist — each answer reshapes which questions still matter; questions that became irrelevant should be dropped, not asked.
The mechanical trigger: when a plan is drafted but unresolved decisions remain, do not start implementation. Identify the most upstream unresolved decision (the one other decisions depend on), state your recommendation with one sentence of reasoning, and ask only that question.
Reference: Pólya — How to Solve It, "The Teacher's Method of Questioning"
If the codebase can answer it, read the codebase — only ask what the source cannot tell you
The interview move (clarify-interview-one-at-a-time) only earns its keep on questions the user actually has to answer. Most "questions" the agent is tempted to ask are not those — they are observable facts about the codebase, the docs, or the runtime. Asking them treats the user's attention as free, signals that the agent has not done the work, and slows the loop. The default to correct: the agent reaches for AskUserQuestion before it reaches for Grep, Read, or running the program.
Tempted to ask:
Q: "What ORM does this project use?"
Should have done:
Read package.json — answered in 2 seconds, no user round-trip.
Tempted to ask:
Q: "What's the auth flow when the token expires?"
Should have done:
Grep for "refresh" + "401" + the middleware path.
Tempted to ask:
Q: "Does the production queue have at-least-once or exactly-once
semantics?"
Should have done:
Read the queue config / provider docs — observable fact.
Genuinely worth asking:
Q: "If the second caller in Q3 sends a duplicate event,
should we dedupe by event_id or accept the duplicate?"
→ A product/policy decision. The code does not contain
the answer because the answer does not exist yet.The discriminator is a one-line test: does the answer already exist somewhere, or is it being decided now? If it exists, find it. If it is being decided, ask — and pair the question with your recommendation per clarify-interview-one-at-a-time. The pathological mix is the worst of both: a wall of questions where three are observable from package.json, two are answered in the README, and the one real product decision is buried at the bottom where the user has already lost patience.
A useful trigger: before sending any question to the user, run the test "could I have answered this with a five-second grep, file read, or runtime check?" If yes, do that first. If no, the question is real and belongs in the interview.
Check dimensional, type, or category consistency
Physicists never write an equation without checking units; the same discipline catches a large class of software bugs before the code runs. The agent's default is to combine quantities by syntax (whatever compiles, whatever the type system allows) rather than by category. When the categories disagree, the result is meaningless even when the program runs.
// Compiles. Looks reasonable. Is silently wrong.
function recordLogin(user: Promise<User>) {
analytics.track('login', { userId: user.id });
// ^^^^^^^
// `user` is a Promise<User>, not a User. `.id` is undefined.
// Categories: Promise<User>.id ≠ User.id. The dimensions disagree,
// even when the TypeScript checker is permissive enough to let it
// through (any-typed callers, optional-chained reads, generated types).
}
// Correct: await before crossing the category boundary.
async function recordLogin(userP: Promise<User>) {
const user = await userP;
analytics.track('login', { userId: user.id });
}The same check catches a large family of bugs that the type system or runtime cannot:
- Adding amounts in different currencies (EUR + USD treated as the same number).
- Mixing tz-naive and tz-aware timestamps in a comparison.
- Adding "duration since epoch" to "duration of this request".
- Comparing UTF-16 code-unit lengths to grapheme counts ("rendered length").
- Dividing "requests" by "window milliseconds" but labelling the result "per second".
- Passing a path relative to one root through an API expecting relative to another.A useful habit: before running the calculation, write the dimensions of every input and the dimension of the output. If the equation cannot produce the output dimension from the input dimensions, the equation is wrong — regardless of what the type checker says.
Reference: Bridgman — Dimensional Analysis (Yale UP, 1922); standard in physics and engineering curricula
Name the invariant — it is usually the answer
By default the agent reasons about how state changes and loses track of what does not. The invariant — the property that must hold at every step — is usually the simplest statement of what the system actually does. Once named, the implementation is a question of "preserve this invariant", and most of the "edge cases" collapse into "moves that would have broken the invariant".
Concurrent reference counter — many threads acquire and release,
the resource is dropped when no one holds it.
Without naming the invariant: argue about CAS loops, fences, ABA,
memory ordering, "what if a release happens during an acquire"…
Invariant: at all times,
count = (number of acquires not yet matched by a release)
AND
count = 0 ⇔ no live reference exists.
Now the design constrains itself:
- Acquire = atomic increment; allowed only if count > 0 (otherwise the
invariant says no reference exists, so there is nothing to acquire).
- Release = atomic decrement; if it brings count to 0, drop the resource.
- The ABA case is impossible because the invariant rules out
"count went 1 → 0 → 1" without a re-acquire from outside the resource.
The CAS subtleties did not go away — they fell out of obeying one line.The invariant is also the documentation: a future reader who knows the invariant can derive the code; a reader who knows the code may never deduce the invariant. Write it in the file.
Reference: Hoare — An Axiomatic Basis for Computer Programming (CACM, 1969)
Decompose along axes that do not entangle
A decomposition is correct when changing one part does not force changes in another. By default the agent splits on convenience — file boundaries, team boundaries, the order things came up in the conversation — and the resulting parts share hidden state across the seams. The test: name a likely future change. If it touches more than one part, the axes are wrong.
Feature-flag system.
Wrong axes (convenience):
flags_for_free_users.ts
flags_for_paid_users.ts
flags_for_internal_users.ts
Future change: "add an 'enterprise' tier" → touches three files,
and any flag that crosses tiers (most of them) lives in all three.
Right axes (orthogonal):
rollout.ts → percentage, ramp, kill switch
targeting.ts → user attributes (tier, region, cohort)
evaluation.ts → bind(flag, user) → bool
Future change: "add enterprise tier" → only targeting.ts. Adding
a new ramp shape → only rollout.ts. The three parts move independently.The axes are usually verbs (rollout, evaluation) and the wrong axes are usually nouns from the current data shape (free, paid, internal). Verbs survive schema changes; today's nouns rarely do.
If renaming the original noun exposes a structurally identical pattern from another domain, the cleaner move is `transfer-cross-domain-analogue`; if the original noun itself is the cage, see `transfer-suspect-vocabulary-lock-in`.
Reference: Parnas — On the Criteria To Be Used in Decomposing Systems into Modules (CACM, 1972)
Specify WHAT before implementing HOW
When specification and implementation are fused, the agent argues about Raft vs. Paxos before it has agreed what "the leader" means. The result is a debate where both sides are right about different problems. Write the WHAT — the externally observable properties — in a paragraph the customer of the code could read, before any line of HOW. The HOW debate then has a referee.
Task: "implement leader election."
WHAT (the spec, ~5 lines, language-independent):
- At most one node is leader at any moment when the network is stable.
- A leader is elected within T seconds of the previous leader's last heartbeat.
- Clients can ask any node who the leader is; the answer is either
correct or "I don't know" (never wrong).
- Network partition: minority side returns "I don't know"; majority elects.
HOW (after the spec is agreed):
- Lease-based: simple, requires loosely synced clocks. ✓ fits.
- Raft: stronger guarantees we don't need. ✗ over-engineered for this.
- Paxos: same. ✗.
Picked: leases. The WHAT made the choice obvious; without it, all three
felt defensible because each is correct for a *different* spec.A useful tell: if the agent cannot write the WHAT in 5 lines without referring to the HOW, the problem is not yet understood. Stop and write it.
Separate essential complexity from accidental complexity
Brooks's distinction: essential complexity is inherent to the problem; accidental complexity is whatever the current tools, libraries, and codebase shape have layered on top. By default the agent treats the codebase's current shape as essential and adds more layers to fit it. Naming each piece as one or the other surfaces what can be moved out, replaced, or skipped versus what must be solved on its merits. Brooks's own thesis was that in mature systems essential complexity already dominates and no 10× lever hides in accident; in fresh and AI-generated code, accidents accrete faster, so the distinction earns its keep most heavily there.
Function: processOrderWithRetryAndIdempotencyAndAnalytics(order, retryCount, idempotencyKey, analyticsCtx)
Essential to "process an order":
- Validate, reserve inventory, charge payment, write order row.
Accidental (could be moved out without changing what processing means):
- Retry → the queue's job; the function should be idempotent and fail fast.
- Idempotency key → a wrapper / middleware concern.
- Analytics context → a side effect emitted from a single layer above.
After separation, the essential function is ~20 lines and the accidents
sit on the call edge where they can be reasoned about independently.The test: if a piece of complexity would still exist if you rewrote the system from scratch in a different language and stack, it is essential. If it would not, it is accidental — and a candidate to push out, not solve harder.
Find the decision the answer must change
Hamming's question — "What is the most important problem in your field, and why aren't you working on it?" — has a sibling for any concrete request: what decision will be made differently depending on the answer? If no decision changes, the work is theatre. If the decision is "ship vs. don't ship in this release", the real question may be different from the literal one.
Literal question: "How long will this migration take?"
Decisions the answer feeds:
1. Whether to ship in the May release (cut date: 3 weeks).
2. Whether to staff a second engineer.
3. Whether to communicate downtime to customers.
If the answer is "6 weeks", decision 1 is "no" — and the real question
becomes "Is there a degraded subset we can ship in 3 weeks that
unblocks the customer ask?" Answering the literal question alone
leaves the team with "6 weeks" and no path forward.Phrase the answer in terms of the decision: "If you can move the cut date by 2 weeks, yes; otherwise we ship phases 1 and 2 only and finish 3 in June." That is what the asker actually needed.
Reference: Hamming — You and Your Research
Restate the problem in your own words before solving
By default the agent paraphrases the prompt and starts solving, which silently locks in whatever the prompt encoded — including the parts that are wrong. A short restatement, surfaced back to the user before any code, exposes the unstated assumptions while they are still cheap to change.
User: "Build a queue for failed webhook deliveries."
Restated before solving:
- Each event must reach the receiver at least once, in original order,
with at most 5 retry attempts over 24h.
- "Failed" = HTTP 5xx or timeout; 4xx is permanent and goes to a DLQ.
- Burst tolerance: 1000 events/sec, sustained 100/sec.
- Out of scope: webhook signing, receiver auth, fan-out to multiple URLs.
Does this match what you need? In particular, is "in original order"
a real constraint, or can a later event overtake a stalled one?Half the time, restating reveals that "order" was assumed but not needed, or that 4xx is also retryable, or that the real problem was duplicate deliveries — not failed ones. Solving the original prompt would have produced a correct answer to the wrong question.
Generalize until the specific problem dissolves
Grothendieck's image: instead of breaking a nut by force, submerge it — raise the surrounding water until the shell softens and the nut opens almost without pressure. When a specific problem resists, the harder, more abstract version is often easier, because the abstraction strips away the incidental features that made the specific case confusing. By default the agent attacks the specific problem harder. Sometimes the move is the other direction: solve a more general problem and the specific one is a corollary.
Problem (specific, resisting):
"Detect this one type of N+1 query in this one ORM, where a hasMany
relation is accessed inside a forEach over the parent collection."
A direct detector for this case requires pattern-matching the ORM's
specific call syntax, its lazy-loading hooks, its association config.
Brittle, and breaks the moment someone uses .map instead of .forEach.
Generalize (rising sea):
"Detect any database query whose call site is inside a loop, where
the query's filter depends on the loop variable."
Generalizing further:
"Detect any sub-linear aggregate operation (a query, an RPC, a file
read) executed inside a linear traversal of a collection whose
element identifier the operation parameterizes."
The most general version drops every reference to "ORM", "hasMany",
and "forEach". The detector becomes: "static-analyze for I/O calls
inside loops where the loop binding flows into the call's arguments".
That detector also catches the original case — and N+1 over plain SQL,
N+1 in an RPC fan-out, and N+1 in file reads. One detector, three bugs.The rising sea is a simplification move, not a complication move. The test for correct generalization: the abstract version has fewer concepts than the specific one, not more. If your generalization needed extra parameters, type variables, and "configuration", you are not generalizing — you are accreting. Stop and go back to the specific.
Reference: Grothendieck — Récoltes et Semailles ("la mer qui monte")
Assume the design failed and find the most likely cause
Jacobi's rule, popularized by Munger: invert, always invert. Designs reviewed for "what makes this succeed?" enumerate features and look complete. The same design reviewed as "imagine it is six months from now and this is the postmortem — what was the most likely root cause?" exposes the failure modes that the success-side review missed. The two reviews catch different bugs.
Deploy script review.
Success-side question: "What does this do?"
Build, test, push image, update service, watch metrics for 5min, done.
Looks fine.
Inverted question: "It's six months from now. We're in a postmortem
because a deploy took prod down. What is the most likely chain?"
Most likely root causes, in observed-frequency order:
1. Health check passed because /health was hard-coded to 200, even
though the service was broken. → add real readiness probe.
2. Canary metric window was too short; regression appeared at 6min,
script returned at 5min. → widen window, or compare against the
previous deploy's same-time window.
3. Rollback didn't actually roll back because the previous image
had been GC'd. → pin previous N images.
4. Two deploys raced; the second one overwrote the first's rollback
target. → serialize, or use deploy IDs.
These four failure modes are all invisible to the "what does this do?"
review and obvious to the inverted one.A useful prompt: write the postmortem before writing the design, in the form "On {date}, X happened because Y, which our pre-deploy checks missed because Z." The Zs are the holes to fill.
Reference: Munger — A Lesson on Elementary, Worldly Wisdom (USC Business School, 1994)
Work backwards from the goal when forward search exhausts
The default is forward search: take the current state and explore outward. When the state space is large and the goal is narrow, this is exponentially harder than the reverse. Working backwards from the goal — what must be true one step before the goal? two steps before? — narrows the search to states that could reach it, and often makes the path obvious.
Goal: checkout p99 latency < 200ms. Currently 480ms.
Forward search (the default trap):
Profile, find the slowest line, optimize it, re-measure, repeat.
Often shaves 50ms over a week and stalls.
Backwards search:
Budget the 200ms across the layers it must pass through:
DB queries 80ms
app logic 40ms
network RTT 40ms
template render 40ms
────
200ms
Measure each layer against its budget:
DB queries 320ms ← 4× over
app logic 30ms ✓
network RTT 50ms slightly over
template 80ms 2× over
The over-budget items name themselves; the search collapses
from "everything" to "DB and templates".This is Pólya's "What must be true just before the goal?" applied to engineering. The forward agent asks "what can I do next?" — combinatorial. The backward agent asks "what must have been true one step before success?" — usually unique or near-unique.
Reference: Pólya — How to Solve It, "Working Backwards"
Probe limit cases — zero, infinity, empty, identity
Physicists check what happens at the boundary because the boundary is where the structure of a system becomes legible. The same trick works on designs and code: ask what happens at 0, ∞, the empty input, and the identity case before writing the general logic. The agent that skips this consistently ships designs that degrade in unexpected ways at the extremes — exactly where users hit them.
Designing a rate limiter: permits per second.
permits = 0 → blocks forever? returns immediately? errors? Pick one,
on purpose, and write it in the spec.
permits = ∞ → does the implementation even take this path, or does it
collapse into "no limiter"? If it should, prove it.
window = 0 → division by zero, or "instant refill"? Different choices
imply different code paths.
duration = 0 → identity case: same start and end. Most aggregation bugs
live here.
empty input → empty output, or error, or sentinel? An empty list of
permits to issue is a different shape than "0 permits".These four probes catch most "the design works on the example, then production input is weirder" bugs without running the code. If the limit-case answer is "we just won't hit that," write down why — that assumption is now part of the design.
Reference: Pólya — How to Solve It, "Specialization" heuristic (Princeton UP, 1945)
Cut to the 20% that produces 80% of the result
The default failure mode is enumeration: the agent lists every case, handles every branch, supports every option. Most of the cost goes to inputs that are rare or unimportant. Find the 20% — by counting calls, measuring traffic, or asking the user which cases actually matter — and design for that. The rest can be a fallback path, a not_supported error, or deferred entirely.
Endpoint cache design across 47 routes.
Measured: 3 routes account for 91% of read traffic:
GET /users/me (54%)
GET /feed (24%)
GET /notifications (13%)
Pareto cut:
Cache those three behind a per-user invalidation key.
Leave the other 44 routes uncached — they cost more to invalidate
correctly than they cost to serve hot.
Result: 91% of traffic absorbed by ~150 lines of cache logic.
Enumerating all 47 would have been ~3000 lines and a stale-data
incident, for 9% more coverage.This is not laziness — it is honest pricing. Every uncommon case the agent supports trades real complexity (which costs forever) for marginal coverage (which often costs nothing because the case never occurs). Knuth's "premature optimization" applies to the choice of what to make complicated, not just to micro-tuning.
Reference: Knuth — Structured Programming with go to Statements (ACM Computing Surveys, 1974)
Solve the smallest non-trivial case fully before generalizing
By default the agent attacks the general N case directly. The general case carries every parameter at once, so failures could come from any of them and the agent flounders. Solving n=1 (or the smallest case where the problem is still genuine — n=2 if n=1 is degenerate) fully, including the corner cases, surfaces the structure; the general algorithm then usually falls out as a fold over the small case.
Problem: reconcile balances across N accounts moving through M intermediaries.
Don't: jump to "build a graph, walk edges, sum at sinks".
Toy case: N=2 accounts (A, B), M=1 intermediary (X).
A → X: -100
X → B: +100
Reconciled when sum(A) + sum(B) + sum(X) = 0 AND sum(X) = 0 in steady state.
What this exposes:
- In-flight transfers are the source of imbalance, not the algorithm.
- The interesting state is "X's pending balance", not "edges in a graph".
- Generalizing to N>2 is a sum; generalizing to M>1 is a sum-of-sums.
General algorithm now: "every node's net = 0, every intermediary's
in-flight = 0". One line, found via the toy case.If the toy case feels trivial or boring, you have picked it correctly. The point is not to solve a small thing — it is to make the structure of the big thing visible.
Reference: Pólya — How to Solve It (Princeton UP, 1945)
Find a structurally identical solved problem in another domain
The default failure mode is staying inside the domain: a webhook problem is "solved" with webhook-y patterns, a database problem with database-y patterns. But most problems have structural twins in domains where someone has already done the hard work — and the twin's vocabulary often points to a much simpler design than the home domain offers.
Problem: deduplicate webhook deliveries — the receiver may see the same
event twice if our delivery service retries after the receiver already
processed it.
Stay-in-domain answer: build a "delivered events" table at the sender,
mark each delivery as it goes out, check on retry.
Cross-domain analogue: this is exactly TCP's retransmit problem.
TCP solves it with:
- sequence numbers (monotonic IDs per stream)
- the receiver dedupes by sequence number
- the sender retries until acked
Applied back to webhooks:
- sender attaches a per-stream monotonic event_id
- receiver stores last_processed_event_id per stream and ignores duplicates
- sender retries on missing ack
The TCP version pushes dedup state to the receiver (where it belongs:
the receiver knows what it has processed). The stay-in-domain version
put it at the sender and would have failed when the receiver was
replaced or its DB was restored from a snapshot.Useful prompts to invoke the search: "where else does someone process events that might arrive twice?" (TCP, idempotent HTTP, message queues, double-entry accounting). "Where else is this kind of constraint enforced?" (databases, type systems, physics conservation laws). Pattern-matching across domains is what Hofstadter calls "the fuel and fire of thinking" — it is also the source of most elegant designs.
Reference: Hofstadter & Sander — Surfaces and Essences (Basic Books, 2013)
Suspect the surrounding vocabulary when stuck
A domain's vocabulary silently constrains the solution space to what that vocabulary can name. Once a thing is called a "Service", the next move is a "Repository" and a "Manager" — even when those abstractions are wrong for the actual work. By default the agent inherits whatever names are already on the page. When stuck, the first thing to suspect is that the names are wrong.
A class called OrderService with 12 collaborators:
OrderRepository, PaymentGateway, InventoryService, ShippingService,
EmailService, AnalyticsService, RetryQueue, IdempotencyStore,
FraudCheck, TaxCalculator, AuditLog, FeatureFlags.
Inside it: a 400-line method orchestrating a long state transition
with try/catch around each call. New requirements keep adding parameters.
What the names hint:
- "Service" implies a stateless function on data.
- This thing is stateful (transitions an order through phases).
- Most of its complexity is orchestration, not service logic.
Drop the vocabulary, name what it actually is:
- It is a workflow / saga / order lifecycle.
- Workflow vocabulary brings: steps, compensations, durable state,
each step's pre/post conditions.
- Now the 400-line method becomes a workflow definition, the
catches become compensations, the IdempotencyStore is the
workflow runtime's job.
Same problem. Different vocabulary. The solution space the new
vocabulary opens did not exist in the old one.A diagnostic: if you keep adding suffixes (Handler, Manager, Coordinator, Helper) to break out responsibilities, the original noun is wrong. Reach for a different vocabulary — workflow, stream, ledger, automaton, schema — and see what falls out.
If the new vocabulary also suggests a different way to split the system, follow it into `decomp-orthogonal-axes` — the right vocabulary often reveals the right axes for free.
Reference: Hadamard — The Psychology of Invention in the Mathematical Field (1945, Princeton UP)
Related skills
FAQ
What does radical-simplification do?
radical-simplification is a Claude Code skill for ai & agent building. It helps developers move faster with AI-assisted coding.
When should I use radical-simplification?
When you need to helps with ai & agent building tasks during ai-assisted development, or when radical-simplification is a claude code skill for ai & agent building. it helps developers move faster with ai-assisted coding.
What are the main capabilities?
radical-simplification; AI & Agent Building; AI-coding skill.