Interface Design
Design It Twice — spawn 3-4 parallel sub-agents producing radically different interfaces for a module, then compare on.
Kit Context
Before starting:
- Read
CODEBASE_MAP.mdfor project understanding - Read
CLAUDE.project.mdif it exists for project-specific rules - Read
agent_docs/architecture-language.md— required. This skill speaks its vocabulary. - Read
tasks/decisions.md— don't re-litigate ADR-resolved interface decisions.
If agent_docs/architecture-language.md hasn't been read in this session, read it now.
When to Use
Invoke with /interface-design <module> when:
- After
/deepening-reviewsettles on a deepening candidate and the user wants to see alternative interface shapes before committing - A new module is about to be created and the first interface idea feels under-explored
- An existing interface is being rewritten and "design it once" feels insufficient
- You catch yourself converging on the first plausible interface — that's exactly when this skill earns its keep
Based on Ousterhout's "Design It Twice": your first interface idea is unlikely to be the best. Spawning parallel agents with different constraints produces designs you wouldn't have reached by iterating sequentially on one.
When NOT to Use
- Trivial modules (a 3-line utility doesn't warrant 3 competing designs)
- When the interface is dictated by an external contract (HTTP spec, protobuf, third-party SDK shape) — there's nothing to design
- When the user has already committed to a shape and just wants implementation help
Hard Rules
- Use
architecture-language.mdvocabulary when classifying the module being designed. Don't substitute "service / boundary / component" for module / seam / interface in your reasoning or in sub-agent briefs. (Descriptive uses — referring to Stripe as a "third-party service" — are fine.) - Spawn at least 3 sub-agents in parallel. Two designs collapse into a binary; three produce real contrast.
- Each sub-agent must produce a radically different design. If two come back similar, re-spawn one with a sharper constraint.
- The user reads while sub-agents work — don't block.
- End with an opinionated recommendation. Not a menu.
Process
Phase 1: Frame the Problem Space
Before spawning sub-agents, write a user-facing brief covering:
- The module being designed — name, purpose in domain language
- Constraints — invariants, ordering, error modes any interface must respect
- Dependencies — categorized per
deepening-review/references/dependency-categories.md - Code sketch — a rough illustrative shape (not a proposal — just enough to ground the constraints)
- What the deepened module hides — the complexity behind the seam
Show this to the user. Don't wait for them to read it — proceed to Phase 2 immediately. The user reads while sub-agents work in parallel.
Phase 2: Spawn Sub-Agents in Parallel
Use the Agent tool. One message, multiple tool calls — they must run concurrently.
Each sub-agent gets:
- The shared technical brief (file paths, dependency categories, what's behind the seam, vocabulary requirements)
- A different design constraint that forces radical divergence
Standard four constraints (use 3 if the fourth doesn't apply):
| Agent | Constraint |
|---|---|
| Minimal | Aim for 1-3 entry points maximum. Maximize leverage per entry point. Anything that can be expressed as a parameter rather than a method, must be. |
| Flexible | Maximize flexibility and extension points. Optimise for use cases not yet imagined. Hooks, middleware, callbacks welcome. |
| Common-Case | Optimise for the most common caller. The default case must be trivially callable; advanced cases can require more setup. |
| Ports & Adapters | Design assuming Category 3/4 dependencies. Define ports at the seam. Production adapter and test adapter both real. |
Drop "Ports & Adapters" if dependencies are all Category 1/2. Replace with State-Machine (model the module as explicit states + transitions) or Functional-Core (push as much as possible into pure functions; thin imperative shell) if either is a better fit for the problem.
Each sub-agent must output:
## Interface
[Types, methods, parameters — plus invariants, ordering, error modes, configuration]
## Usage Example
[Realistic code showing how a caller uses it]
## What's Behind the Seam
[What the implementation hides — including internal seams not exposed by the interface]
## Dependency Strategy
[Per-dependency: category + adapter strategy if applicable]
## Trade-offs
[Where leverage is high. Where it's thin. What's deliberately hard.]Phase 3: Present and Compare
Don't dump three designs at once. Present them sequentially so the user can absorb each one:
## Design 1 — [Constraint name]
[Sub-agent's output, lightly cleaned for formatting]
## Design 2 — [Constraint name]
[...]
## Design 3 — [Constraint name]
[...]Then compare in prose along three axes:
- Depth — leverage at the interface. Which design lets callers do the most per unit of interface they have to learn?
- Locality — where change concentrates. Which design means a typical change touches the fewest files?
- Seam placement — where the interface lives. Which design puts the seam where it actually needs to vary?
The comparison is structured but the verdict is editorial. Don't hide behind "it depends."
Phase 4: Recommend
Give your own pick. Be opinionated.
## Recommendation
**Pick: Design N**
Reasoning:
- [Why this design wins on the axis that matters most for *this* module]
- [What you accept losing by not picking the others]
- [What hybrid elements (if any) are worth borrowing from rejected designs]
If the user disagrees with the choice of axis, the verdict can flip — call that out:
*"If [different priority] is actually the most important constraint, Design M wins instead."*If two designs combine well, propose a hybrid explicitly — don't just say "could be combined." Sketch the merge.
Phase 5: Hand-off
Once the user picks (your recommendation or otherwise):
- Write the chosen interface to
tasks/todo.mdas the planned shape - If this came from
/deepening-review— update the deepening task with the chosen interface - If the rejected designs surface load-bearing reasons not to take them — offer ADRs in
tasks/decisions.md
Implementation goes through the kit's normal Plan First → confirmation → execution flow. This skill ends at "we know the interface."
Output Format
# Interface Design — [Module Name]
## Problem Space
[Frame: constraints, dependencies, sketch, what's behind the seam]
[Sub-agents working in parallel...]
## Design 1 — Minimal
[Output]
## Design 2 — Flexible
[Output]
## Design 3 — Common-Case
[Output]
## Comparison
[Prose comparison: depth / locality / seam placement]
## Recommendation
[Opinionated pick + reasoning + optional hybrid]Common Rationalizations
| Rationalization | Reality |
|---|---|
| "I already know what the interface should be" | Then Design It Twice is exactly when you should run this skill. The cost of three sub-agents is small; the cost of an interface that locks in a worse design is large. |
| "All three designs converged on the same thing" | Then either the constraints were too narrow or the sub-agent briefs weren't divergent enough. Re-spawn with sharper constraints. |
| "Let the user pick — they know best" | The user wants a strong read, not a menu. They can override your pick, but they need an opinion to push against. |
| "The interface doesn't matter — implementation does" | The interface is what callers see, what tests exercise, what survives implementation rewrites. It matters more than the implementation. |
| "I'll just iterate after shipping v1" | Interfaces calcify the moment a second caller depends on them. The cost of changing an interface scales with caller count. Get it right before shipping. |
Notes
- This skill leans heavily on parallel sub-agent execution. Verify all three are spawned in one message with multiple
Agenttool calls — sequential spawning loses the parallelism that makes this useful. - Inspired by John Ousterhout's A Philosophy of Software Design (Design It Twice principle) and the improve-codebase-architecture skill by Matt Pocock.
- Pairs with
/deepening-review(which finds the candidate) and/refactoring-guide(which sequences the implementation).