- name
- architect
- description
- Design the shape of a non-trivial module, API, or system before implementing it. Use when a design decision has more than one reasonable answer, when introducing a new abstraction or interface, or when getting the shape wrong would be expensive to undo.
```
█████╗ ██████╗ ██████╗██╗ ██╗██╗████████╗███████╗ ██████╗████████╗
██╔══██╗██╔══██╗██╔════╝██║ ██║██║╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝
███████║██████╔╝██║ ███████║██║ ██║ █████╗ ██║ ██║
██╔══██║██╔══██╗██║ ██╔══██║██║ ██║ ██╔══╝ ██║ ██║
██║ ██║██║ ██║╚██████╗██║ ██║██║ ██║ ███████╗╚██████╗ ██║
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═╝
```
# Architect the shape first
Code is easy to write and hard to reshape. The interface you choose outlives the implementation. This skill produces a deliberate design instead of the first one that compiles.
## 1. Search before you build
Before designing anything custom, decide where this work belongs on the ladder:
- **Adopt** — a library/tool already does this well. Use it.
- **Extend** — something close exists; extend it.
- **Compose** — combine existing pieces.
- **Build** — only when the above genuinely don't fit.
Check package registries, the existing codebase, and installed skills/MCP tools first. Report what you found and why you're building rather than adopting. Most "new" problems are solved problems.
## 2. Design it twice (at least)
Never ship the first design. Generate **2-3 genuinely different** designs, each forced apart by a *different constraint*:
- minimize the interface surface
- maximize flexibility
- optimize the common case
- imitate a known, well-understood paradigm
- survive failure well (idempotency, partial-failure, retries, backpressure)
If subagents are available, dispatch them in parallel — one design each — so the options don't converge. Then compare.
## 3. Judge on depth, not effort
- A **deep** interface is small but hides significant complexity (good). A **shallow** one is a large surface over a thin implementation (bad — it just relocates complexity onto callers).
- Optimize for **ease of correct use** and **hardness of misuse**.
- Do **not** rank designs by how much code they take to implement — that's the cheapest part and the wrong axis.
- **Record the decision, including the losers.** Output a short comparison (each design × how it scores on the constraints / its key failure mode) and one sentence per rejected design saying exactly why it lost. A design chosen with no written loser isn't a decision — it's the first thing that compiled.
## 4. Earn every abstraction
- **Deletion test:** imagine deleting this module. If the same complexity reappears, duplicated across N callers, the module earned its place. If not, you're abstracting for its own sake — don't.
- **Two-adapter rule:** one adapter is a *hypothetical* seam; two real adapters prove a seam exists. Don't introduce an interface for a single implementation "in case." (This is `forge:principles` #2 applied to structure.) **Exception:** a test double or an external-boundary port (network, clock, third-party API, persistence you'll mock in tests) *is* the second adapter — seam it.
## 5. Name and record
- Name every concept in the project's **ubiquitous language** — one canonical term per idea, aliases explicitly retired. Update CONTEXT.md.
- Record an **ADR** only when the decision is hard to reverse *and* surprising without context *and* a real trade-off. Capture the *decision and why*, not file locations (those rot).
## Exit
Hand the chosen shape to `forge:plan` to break into vertical slices, then `forge:tdd` to build.
عرض على GitHub