Install
$ agentstack add skill-celestialdust-achilles-skills-codebase-design ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
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, and
docs/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.md gives 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.md under the slice that owns the module. If the boundary is hard-to-reverse ∧ surprising ∧ a real trade-off, record it as an ADR via documentation-and-adrs and reference it by id from plan.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.
```typescript // Testable function processOrder(order, paymentGateway) {}
// Hard to test function processOrder(order) { const gateway = new StripeGateway(); } ```
- Return results, don't produce side effects.
```typescript // 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
from plan.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 no STATE.md row 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--.mdviadocumentation-and-adrs;plan.md
references 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.md points to both.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: celestialdust
- Source: celestialdust/achilles-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.