Staged decomposition
An Agent Skill that stops coding agents jumping straight to the finish line. Forces a written A -> B -> C -> D decomposition before any implementation code.
npx -y skills add Juliusolsson05/staged-decompositionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 16 days oldThe repository was created 16 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Forces a written stage decomposition before any implementation code is written for a complex feature, and requires tests to be built from recorded real data rather than imagined cases. Use when implementing or refactoring a non-trivial feature in a large codebase (roughly 35k+ LOC), when a previous attempt got to 40-70% and stalled, when bugs are being fixed by adding conditionals to existing code, when multiple data sources or providers must agree on one output, when a feature is spread across far more files than it should be, or when the user asks to redesign, untangle, or isolate a subsystem.
SKILL.md
10.7 KB, as published. Nobody here has run it
Staged Decomposition
Implementation may not start until a written decomposition exists and the user has approved it.
This skill encodes a methodology, not a checklist. Read the reasoning — the rules only work if you understand what they are defending against.
When this applies
Apply when both are true:
- The codebase is large enough that tech debt compounds — roughly 35k+ LOC
- The feature is not surface-level CRUD. It has unclear shapes, multiple data sources, or edge cases nobody has enumerated yet
Skip when the codebase is under ~20-35k LOC, or the change has a known shape. Below that threshold raw model capability handles the work and the tech debt is too small to matter; this process is pure overhead. Say you are skipping and why, then proceed normally.
A skill that fires on trivial work gets ignored on real work. Be honest about the threshold.
The failure this prevents
Asked to get from A to D, models go straight to D.
What comes back looks great on the surface and is roughly 40% correct. It handles the cases that happened to be in context. Then:
- You use it, spot a bug, ask for a fix. An
ifstatement gets added. - You spot another bug. Another
ifstatement. - The percentage creeps: 50, 60, maybe 70.
- Then it stops working. In a system that isn't surface-level CRUD, each new change breaks something buried elsewhere.
At that point you are playing whack-a-mole with a codebase that is degrading with every prompt. The way out is not more prompting. There is no sequence of bug reports that converts a wrong substrate into a right one.
This is not an intelligence problem. It is a workflow problem. The fix is to fill the vacuum in the middle: A → B → C → D.
Why the middle gets skipped
Understanding this mechanism matters more than memorising the rules.
Intermediate stages produce nothing visible. A recorder renders no element on screen. A catalog renders no element on screen. To a process optimising for output the user can see, the entire middle of the road looks like empty air — so it drives straight through.
Forward-patching never has to admit defeat. A model optimises forward from whatever structure already exists. It will squeeze the next fix into that structure indefinitely. What it will not do on its own is stop and say:
"This whole substrate is wrong. We need to tear it out and build the boring invisible thing first."
That sentence requires declaring the current work a dead end. Forward-patching never has to make that call, so it never gets made.
Consequence: roughly half the structural groundwork has to come from the human. Not because the model lacks capability on the granular level — it is excellent there — but because it cannot reliably conclude that the structure it is standing on is the thing that's wrong.
The highest-value human intervention in agentic development is deciding to do something slower in order to do it correctly.
The method
What counts as a stage
Each stage must declare all four fields. A stage that cannot fill all four is not a stage:
| Field | Requirement |
|---|---|
| Produces | A named, inspectable artifact — a file, a dataset, a catalog. Not "understanding," not "a better grasp of the problem." |
| Verified by | How you know it is correct without depending on any later stage |
| Why separate | What breaks if this is merged into the next stage |
| Reality check | What real, collected evidence it is built from |
Enumerate from reality, not from imagination
This is the rule that does the most work.
When the set of cases is unknown, the first stage is almost always instrumentation: record what actually happens during real use, with frequencies. Only then build a catalog of what was observed. Only then implement, one case at a time.
If you implement against cases you assumed, you will handle the shapes that were in your context and silently omit the rest. That is the mechanism that produces exactly 40%.
The instrumentation stage is the single highest-value step and the one most likely to be skipped, precisely because it produces nothing visible.
Isolate the hard part
Name the genuinely hard component and confine it. Give it:
- Its own directory or module
- A single consumer — the next stage, and nothing else
- An explicit list of what is now forbidden from importing it
When multiple sources of truth must be reconciled, the reconciliation belongs in its own isolated layer that emits one clean object. It does not belong distributed across the consumers. Consumers that each arbitrate between sources will fight each other, and the resulting bugs — duplicated entries, items vanishing, ordering that changes between runs — will appear to be rendering bugs while actually being ownership bugs.
See reference/structure-and-isolation.md for how to judge whether something is isolated.
Tests and fixtures
AI-written TDD is usually worthless, and it is worse than no tests because it manufactures false confidence.
The failure mechanism is precise. A model decides what the code does, then writes tests asserting exactly that. The suite goes green. It proves nothing except that the code does what the code does. The tests were written from the same imagination that wrote the bug, so they encode the same misunderstanding.
This is a vanity metric. It creates the illusion of a stable codebase. A real case: a rendering implementation that was fundamentally broken passed 481 of 481 tests.
Test count is not evidence. Passing tests written after the fact, by the same process that wrote the implementation, against imagined inputs, are not evidence either.
What makes tests real
Fixtures must come from recordings of actual system behaviour. This is why instrumentation is stage one — it produces the corpus the tests are built from. A fixture is a captured real input, not a plausible-looking literal someone typed.
Write the tests before the implementation, against those fixtures. TDD is genuinely the right approach for complex reconciliation logic. What makes it work is the fixtures being real. What makes it theatre is the fixtures being invented.
Do not delete or weaken a failing test to get green. A failing test against a real fixture is the most valuable artifact in the process. It is the thing that told you the substrate was wrong.
The human must be involved here. Writing proper tests for deeply integrated components requires fundamental understanding of the system's own semantics — what should own a given piece of state, what should happen when two sources disagree. Ask for that judgement rather than inventing it. If you invent the semantics, you will then write tests that bless your invention.
Full methodology in reference/tests-and-fixtures.md.
Required artifact
Write docs/decomposition/<feature>.md before any implementation code:
1. A and D stated concretely
- A — what exists and is trusted, named as a specific file, object, or output
- D — the end state in terms of observable behaviour
2. The intermediate stages — each with the four fields above
3. What is being isolated — the hard part, where it will live, what may not import it
4. Unknowns — shapes, cases, or behaviours not yet enumerated. If this list is empty you have not looked hard enough. Say so explicitly rather than leaving it blank.
5. Fixture plan — where the real data for tests comes from, and which stage produces it
Workflow
- Confirm the skill applies. If not, say so and proceed normally.
- Investigate the current state. Read the relevant code before proposing stages.
- Write the decomposition to
docs/decomposition/<feature>.md. - Stop. Present it and get explicit approval. No implementation code in this step.
- Implement one stage at a time. After each, confirm its artifact exists and is independently verified before starting the next.
- If a later stage reveals the decomposition was wrong, stop and revise the document. Do not patch forward.
Red flags
These thoughts mean the shortcut is being taken:
| Thought | Reality |
|---|---|
| "I can see the whole thing, I'll just build it" | You can see the shapes that are in context. Not the ones that aren't. |
| "I'll add the recorder afterwards if needed" | Afterwards, the implementation is the substrate and the recorder can no longer change it. |
| "The tests pass" | Written by whom, from what data? |
| "I'll write fixtures that look like real data" | Then you are testing your imagination. |
| "This stage produces nothing visible" | Correct. That is why it is the one being skipped. |
| "I'll handle that edge case with a conditional" | A second conditional means the substrate is wrong. Stop. |
| "The user wants to see progress" | They want the feature finished, not 70% and collapsing. |
| "This test is wrong, I'll adjust it" | Against a real fixture, the test is right and the code is wrong. |
| "Refactoring this properly is out of scope" | Naming the dead end is the one thing forward-patching never does. |
What good steering sounds like
Prompt engineering is system design in disguise. Phrasing rituals — "you are a senior software engineer" — do nothing. What actually changes outcomes is structural direction:
"It feels like our rendering system is spread out over the codebase. Should we not take this and isolate it into its own
/renderingdirectory?"
Giving more context about a feature improves results. The formatting of that context does not matter. Expect and invite this kind of correction — a good codebase is built from a chain of these observations, not from one perfect prompt.
References
Source essay: Misadventures in Agentic Development
- reference/tests-and-fixtures.md — the fixture methodology in full
- reference/structure-and-isolation.md — modularisation, untangling, LOC thresholds
- reference/worked-examples.md — two real cases, end to end