Codebase design
An AI engineering skill suite that takes one idea from Ideate → Spec → Plan → Implement → Verify → Review → Ship — the human owns intent, the agent owns execution, ending at risk-banded draft PRs. Installable across Claude Code, Cursor, Gemini CLI, and more.
npx -y skills add celestialdust/achilles-skills --skill codebase-designAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 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
Shared vocabulary and method for designing deep modules — a lot of behaviour behind a small interface, at a clean seam, testable through it. Use when planning a module's interface during plan-breakdown, when the user wants to design or improve an interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary. Reach for it BEFORE you write interface signatures into plan.md — designing the seam after the code exists is too late.
SKILL.md
12.7 KB, as published. Nobody here has run it
Purpose
Stage: Plan — referenced discipline, not a sequential stage. plan-breakdown owns the plan;
this skill is the design language and method it (or a standalone refactor) applies when shaping a module's
interface.
Design deep modules: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Depth buys three things — leverage for callers (more capability per unit of interface they must learn), locality for maintainers (change/bugs/knowledge concentrate in one place), and testability for everyone (callers and tests cross the same seam). The exact, shared vocabulary below is the point: inconsistent words ("component", "service", "boundary") are how design conversations quietly go wrong.
When to use / when to skip
Use during plan-breakdown when you're deciding a module's interface or where a seam goes, or standalone
for a pure refactor (deepening a cluster of shallow modules). Use it whenever another skill needs the
deep-module vocabulary so everyone names things the same way.
Skip when there's no real module to shape — a one-line config change, a pure data migration, trivial glue. Escape hatch: do not introduce a seam for a single adapter ("one adapter = hypothetical seam; two = real") — that's just indirection, and this skill will tell you so.
Inputs
- The deepening candidate — a named module, a cluster of shallow modules, or the interface you're
about to write into
plan.md, plus a sketch of the behaviour that sits behind it. - Its dependencies — so you can classify them (in-process / local-substitutable / remote-but-owned /
true-external) per
references/DEEPENING.md. CONTEXT.md(repo-root glossary — its## Glossarysection) for ubiquitous-language names, anddocs/adr/for prior boundary decisions, so the interface you name is consistent with the project.
Refuse to run if there is no concrete candidate. You cannot design depth in the abstract — ask
plan-breakdown or the user to name the module and what sits behind it first.
Process
- Name it in the vocabulary. Write the module and its candidate interface using the Glossary terms below. The interface is everything a caller must know — signature plus invariants, ordering constraints, error modes, required config, performance characteristics — not just the type.
- Apply the deletion test. Imagine deleting the module. If complexity vanishes, it was a pass-through; don't build it. If complexity reappears across N callers, it earns its keep. Write down what reappears.
- Push for depth. Can I cut methods? Simplify params? Hide more behind the seam? (See Deep vs shallow.)
- Place the seam, classify dependencies. Decide where the seam lives, then classify each dependency
(in-process / local-substitutable / remote-but-owned / true-external) —
references/DEEPENING.mdgives the testing approach for each. Only define a port when two adapters are justified (prod + test). - Design it twice for load-bearing interfaces. For a high-stakes interface, spin up parallel
sub-agents to produce radically different designs, then compare on depth / locality / seam placement —
see
references/DESIGN-IT-TWICE.md. Your first idea is unlikely to be the best. - Land it in plan.md; promote durable boundaries to ADRs. Write the resulting interface into
plan.mdunder the slice that owns the module. If the boundary is hard-to-reverse ∧ surprising ∧ a real trade-off, record it as an ADR viadocumentation-and-adrsand reference it by id fromplan.md— don't bury a durable decision in plan prose where the gate rubber-stamps it unseen.
Glossary
Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
Module — anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. Avoid: unit, component, service.
Interface — everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. Avoid: API, signature (too narrow — they refer only to the type-level surface).
Implementation — what's inside a module, its body of code. Distinct from Adapter: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
Depth — leverage at the interface: the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is deep when a large amount of behaviour sits behind a small interface, shallow when the interface is nearly as complex as the implementation.
Seam (Michael Feathers) — a place where you can alter behaviour without editing in that place; the location at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. Avoid: boundary (overloaded with DDD's bounded context).
Adapter — a concrete thing that satisfies an interface at a seam. Describes role (what slot it fills), not substance (what's inside).
Leverage — what callers get from depth: more capability per unit of interface they learn. One implementation pays back across N call sites and M tests.
Locality — what maintainers get from depth: change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.
Deep vs shallow
Deep module = small interface + lots of implementation:
┌─────────────────────┐
│ Small Interface │ ← Few methods, simple params
├─────────────────────┤
│ │
│ Deep Implementation│ ← Complex logic hidden
│ │
└─────────────────────┘
Shallow module = large interface + little implementation (avoid):
┌─────────────────────────────────┐
│ Large Interface │ ← Many methods, complex params
├─────────────────────────────────┤
│ Thin Implementation │ ← Just passes through
└─────────────────────────────────┘
When designing an interface, ask:
- Can I reduce the number of methods?
- Can I simplify the parameters?
- Can I hide more complexity inside?
Principles
- Depth is a property of the interface, not the implementation. A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface.
- The deletion test. Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
- The interface is the test surface. Callers and tests cross the same seam. If you want to test past the interface, the module is probably the wrong shape.
- One adapter means a hypothetical seam. Two adapters means a real one. Don't introduce a seam unless something actually varies across it.
Designing for testability
Good interfaces make testing natural:
-
Accept dependencies, don't create them.
// Testable function processOrder(order, paymentGateway) {} // Hard to test function processOrder(order) { const gateway = new StripeGateway(); } -
Return results, don't produce side effects.
// Testable function calculateDiscount(cart): Discount {} // Hard to test function applyDiscount(cart): void { cart.total -= discount; } -
Small surface area. Fewer methods = fewer tests needed. Fewer params = simpler test setup.
Relationships
- A Module has exactly one Interface (the surface it presents to callers and tests).
- Depth is a property of a Module, measured against its Interface.
- A Seam is where a Module's Interface lives.
- An Adapter sits at a Seam and satisfies the Interface.
- Depth produces Leverage for callers and Locality for maintainers.
Rejected framings
- Depth as ratio of implementation-lines to interface-lines (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
- "Interface" as the TypeScript
interfacekeyword or a class's public methods: too narrow — interface here includes every fact a caller must know. - "Boundary": overloaded with DDD's bounded context. Say seam or interface.
Rationalizations
- "I'll design the interface once the code exists." → The interface is the test surface. Designing it after the code means the tests already cross the wrong seam.
- "Add the port now, we might need a second adapter later." → One adapter = hypothetical seam = indirection. Wait for the second to actually exist.
- "It's a small module, depth doesn't matter." → Depth is leverage per unit of interface, independent of size. A small module with a needlessly large interface is still shallow.
- "This boundary decision is fine left in plan.md prose." → If it's hard-to-reverse, it belongs in an ADR, or it gets rubber-stamped unseen at the single Spec/Plan gate.
- "I'll just call it a component / service / boundary." → Inconsistent vocabulary is the exact failure mode this skill exists to prevent. Use the Glossary words.
Red flags — STOP
- You're testing past the interface (reaching into internal state) → the module is the wrong shape; reshape the seam, don't add a back door.
- The interface is nearly as complex as the implementation → shallow module. Deepen it or delete it.
- You introduced a seam/port with exactly one adapter → remove the indirection until a second adapter is real.
- You're measuring depth as impl-lines ÷ interface-lines → rejected framing (rewards padding the implementation); use depth-as-leverage.
- A hard-to-reverse boundary is sitting only in
plan.mdprose → promote it to an ADR before the gate.
Verification (ending criteria)
- Each module's interface is written into
plan.mdin the suite vocabulary, as the full contract (signature + invariants + ordering + error modes + performance), not just a type signature. - Every candidate passed the deletion test, with the reappearing complexity documented.
- Every seam has ≥2 justified adapters, or it isn't a seam (the indirection was removed).
- Dependencies are classified and the cross-seam testing approach is stated (replace, don't layer).
- Hard-to-reverse boundaries are captured as ADRs via
documentation-and-adrsand referenced by id fromplan.md.
Outputs & handoff contract
- Emits: deep-module interfaces in
plan.md(under the slice/step that owns the module) — the registry artifact for this discipline. There is no standalone artifact and noSTATE.mdrow transition: this is a referenced discipline, not a slice. - Stable surface
plan-breakdownconsumes: for each module, the interface description (signature + invariants + ordering + error modes + performance) and its seam/adapter plan (dependency category + prod/test adapters). - Hard-to-reverse decisions →
docs/adr/ADR-<NNN>-<slug>.mdviadocumentation-and-adrs;plan.mdreferences them by id. "Change the shape → update the referrer in the same commit" extends to ADRs. - Going deeper (carried references): deepening a cluster given its dependencies →
references/DEEPENING.md; exploring alternative interfaces with parallel sub-agents →references/DESIGN-IT-TWICE.md.SKILL.mdpoints to both.