clean-arch
Scaffolding and guidance for hexagonal architecture with the Result pattern. Distilled
from two production projects that converged, independently, on the same patterns.
What it does and what it does NOT do
Does: generates the layer structure, the core (Result, error catalog, ports), the
mechanical enforcement of the boundary, the composition wiring, and the feature slices.
Audits existing repos against the same standard.
Which school: it prescribes Clean Architecture's layering — entities separate from use
cases — with Hexagonal's ports-and-adapters vocabulary at the edge, and it also supports
the single-core variant. Which one you get is an interview decision
(--school clean|hexagonal in scripts/scaffold.mjs, default clean).
Does NOT:
- It does not pick your business or write your domain rules. It generates the scaffolding,
you supply the invariants.
- It does not replace
ahk init or autoskills; it invokes them in the right order
(§ Order of operations).
- It does not invent a new architecture. It reproduces a proven one, and tells you when to
deviate.
Modes
| Invocation |
What it does |
/clean-arch |
Decision interview → recommends a preset and waits for confirmation |
/clean-arch fullstack |
Full preset: monorepo + server + web + deploy |
/clean-arch server |
Backend only: packages/domain, packages/application, apps/api |
/clean-arch web |
Frontend only, consuming an existing contract via codegen |
/clean-arch feature <name> |
New feature slice on an already scaffolded project — the most used mode |
/clean-arch audit |
Applies references/audit-checklist.md to an existing repo and reports deviations |
/clean-arch explain <topic> |
Reads the reference and answers. Generates nothing |
/clean-arch tooling |
Bootstrap of ahk + autoskills only, on an existing project |
No argument → starts the interview.
Stack interview
The default stack is: TypeScript · pnpm workspace · Fastify 5 · Zod 4 · Prisma ·
PostgreSQL · Vite + React.
Present it whole and at once, and ask whether it is confirmed as is or some piece
changes. Do not break it into twelve consecutive questions. Swappable pieces:
- Server language — TypeScript (default) · C#/.NET · Java/Spring · Go
- Frontend — Vite+React (default) · Next.js · TanStack Start · none
- DB and ORM, auth, project shape, deployment
Every decision, with its alternative and its real trade-off, is in
references/decisions.md. Consult it when the user questions a
default; do not improvise the trade-off.
Canonical order of operations
Phase A — scaffolding
- Interview → preset and decisions resolved.
- Resolve dependencies — versions via Context7, never from memory (§ Delegation).
scripts/scaffold.mjs — generates the tree from templates/.
pnpm install.
npx autoskills@latest -y — detects the stack by reading package.json, which
is why it goes after installing. Before that it has nothing to read.
scripts/bootstrap-tooling.mjs — ahk init / ahk build, with a fallback if missing.
health.sh must exit green before continuing.
PHASE GATE — read before continuing
- If the project is new (its
.claude/ did not exist when the session started), the
Claude Code watcher does not cover it: you must restart the session inside the
project before implementing anything.
- If
.claude/ already existed, skills and agents are detected hot. Even so: a new
.mcp.json requires a restart, and the block autoskills injects into CLAUDE.md
is only re-injected after /compact.
Detail and diagnosis in references/ops/agent-tooling.md.
Phase B — feature slices
feature <name>, one at a time. Each slice touches the three layers in this order:
entity + errors → port → use cases + bundle → adapter → schema/DTO → route →
tests. Never the other way round: the adapter before the port produces a Prisma-shaped port.
References
Each line states when to read it. Do not load them all at once.
Core — language-agnostic
- references/core/01-layers.md — The three layers, the dependency direction, the composition root and the directory structure. Always read it before creating a new file, to know where it goes.
- references/core/02-result-pattern.md — The
Result type, the propagation idiom and the three sanctioned exceptions to no-throw. Always read it before writing any use case or adapter.
- references/core/03-error-catalog.md — Closed catalog of codes, per-aggregate factories, messages as a wire contract. Read it when defining new errors or when you see a per-feature error
enum.
- references/core/04-use-cases.md — Factory-returning-function,
Deps/Input, per-slice bundle and its surface as a security decision. Read it on every feature <name>.
- references/core/05-ports-adapters.md — What a port is, invariants in doc-comments, when to split it, the row→entity seam. Read it before touching persistence or any external service.
- references/core/06-dto-mapping.md — Anatomy of the schema file,
toXDto/toXInput, present<T>() and correct PATCH. Read it when writing the HTTP layer of a slice.
- references/core/07-testing.md — The port fake with
calls/failWith/guard, the subject() helper, which layer is tested how. Read it before writing the first test of a slice.
- references/core/08-boundary-enforcement.md — The three layers of defence and the mandatory negative test. Always read it when scaffolding, and mandatorily if you touch the linter config.
Stacks — per-language detail
- references/stacks/ts-fastify-prisma.md — The default stack. Read it if the server is TypeScript.
- references/stacks/csharp-dotnet.md — Read it only if the server is .NET.
- references/stacks/java-spring.md — Read it only if the server is Spring.
- references/stacks/go-chi.md — Read it only if the server is Go.
Frontends
- references/frontends/vite-react.md — Default SPA.
- references/frontends/nextjs.md — If there is SSR/RSC.
- references/frontends/tanstack-start.md — If full-stack type-safe routing was requested.
Operations
- references/ops/deployment.md — Containers, single proxy, monorepo build context. Read it when preparing the deployment.
- references/ops/quality-gates.md —
health.sh, CI, per-workspace script coverage. Read it when scaffolding and when auditing.
- references/ops/config-env.md — Variables by trust boundary, environment validation, secret leakage into the bundle. Read it before adding any variable.
- references/ops/agent-tooling.md — ahk, autoskills, and why you sometimes have to restart the session. Read it at the phase gate.
Cross-cutting
- references/decisions.md — The ~12 interview decisions with their trade-off. Read it in interview mode or when someone questions a default.
- references/audit-checklist.md — Actionable checklist with concrete commands. Read it in
audit mode.
Scripts
| Script |
What for |
node scripts/scaffold.mjs <preset> |
Generates the preset tree from templates/ |
node scripts/new-feature.mjs <name> |
New slice across the three layers + tests |
node scripts/check-boundaries.mjs |
Negative test: injects a forbidden import and requires the lint to fail |
node scripts/check-env-secrets.mjs |
Detects privileged credentials exposed to the client bundle |
node scripts/check-coverage.mjs |
Verifies that every workspace declares typecheck/build/test/lint or a documented exemption |
node scripts/bootstrap-tooling.mjs |
ahk init/build + autoskills, with a fallback |
Templates in templates/_root/, templates/packages/, templates/apps/,
templates/deploy/, templates/feature/.
Delegation: library versions and APIs
There is no version knowledge embedded in this skill, and you must not add any.
For the current API, configuration or syntax of Fastify, Prisma, Zod, React, Vite,
EF Core, Spring or any other dependency, consult Context7 MCP
(resolve-library-id → query-docs) before writing the code. The references in
references/core/ describe the pattern, which does not expire; versions do.
1---2name: clean-arch3description: Scaffolds and enforces hexagonal architecture with the Result pattern (no exceptions for expected failures) across backend, fullstack and web projects. Use this whenever the user starts a new backend, API, server or fullstack project; asks for hexagonal architecture, ports and adapters, clean architecture, a domain/application/infrastructure split, a pnpm monorepo, or a Result/Either error model instead of throwing; asks to add a feature, vertical, use case, port, adapter or endpoint to a project that already follows this layout; or asks to audit an existing repository for layering violations, inconsistent error-to-status mapping, or architecture rules that are silently not enforced. Also use when the user mentions Fastify, .NET, Spring or Go server scaffolding with a clean core.4license: MIT5---67# clean-arch89Scaffolding and guidance for hexagonal architecture with the Result pattern. Distilled10from two production projects that converged, independently, on the same patterns.1112## What it does and what it does NOT do1314**Does:** generates the layer structure, the core (`Result`, error catalog, ports), the15mechanical enforcement of the boundary, the composition wiring, and the feature slices.16Audits existing repos against the same standard.1718**Which school:** it prescribes Clean Architecture's layering — entities separate from use19cases — with Hexagonal's ports-and-adapters vocabulary at the edge, and it also supports20the single-core variant. Which one you get is an interview decision21(`--school clean|hexagonal` in `scripts/scaffold.mjs`, default `clean`).2223**Does NOT:**24- It does not pick your business or write your domain rules. It generates the scaffolding,25 you supply the invariants.26- It does not replace `ahk init` or `autoskills`; it invokes them in the right order27 (§ Order of operations).28- It does not invent a new architecture. It reproduces a proven one, and tells you when to29 deviate.3031## Modes3233| Invocation | What it does |34|---|---|35| `/clean-arch` | Decision interview → recommends a preset and waits for confirmation |36| `/clean-arch fullstack` | Full preset: monorepo + server + web + deploy |37| `/clean-arch server` | Backend only: `packages/domain`, `packages/application`, `apps/api` |38| `/clean-arch web` | Frontend only, consuming an existing contract via codegen |39| `/clean-arch feature <name>` | New feature slice on an already scaffolded project — **the most used mode** |40| `/clean-arch audit` | Applies [references/audit-checklist.md](references/audit-checklist.md) to an existing repo and reports deviations |41| `/clean-arch explain <topic>` | Reads the reference and answers. Generates nothing |42| `/clean-arch tooling` | Bootstrap of ahk + autoskills only, on an existing project |4344No argument → starts the interview.4546## Stack interview4748The default stack is: **TypeScript · pnpm workspace · Fastify 5 · Zod 4 · Prisma ·49PostgreSQL · Vite + React**.5051Present it **whole and at once**, and ask whether it is confirmed as is or some piece52changes. Do not break it into twelve consecutive questions. Swappable pieces:5354- **Server language** — TypeScript (default) · C#/.NET · Java/Spring · Go55- **Frontend** — Vite+React (default) · Next.js · TanStack Start · none56- **DB and ORM**, **auth**, **project shape**, **deployment**5758Every decision, with its alternative and its real trade-off, is in59[references/decisions.md](references/decisions.md). Consult it when the user questions a60default; do not improvise the trade-off.6162## Canonical order of operations6364### Phase A — scaffolding65661. **Interview** → preset and decisions resolved.672. **Resolve dependencies** — versions via Context7, never from memory (§ Delegation).683. **`scripts/scaffold.mjs`** — generates the tree from `templates/`.694. **`pnpm install`**.705. **`npx autoskills@latest -y`** — detects the stack **by reading `package.json`**, which71 is why it goes **after** installing. Before that it has nothing to read.726. **`scripts/bootstrap-tooling.mjs`** — `ahk init` / `ahk build`, with a fallback if missing.737. **`health.sh`** must exit green before continuing.7475### PHASE GATE — read before continuing7677- If the project is **new** (its `.claude/` did not exist when the session started), the78 Claude Code watcher **does not cover it**: you must **restart the session inside the79 project** before implementing anything.80- If `.claude/` **already existed**, skills and agents are detected hot. Even so: a new81 `.mcp.json` **requires a restart**, and the block autoskills injects into `CLAUDE.md`82 is only re-injected after `/compact`.8384Detail and diagnosis in [references/ops/agent-tooling.md](references/ops/agent-tooling.md).8586### Phase B — feature slices8788`feature <name>`, one at a time. Each slice touches the three layers in this order:89entity + errors → port → use cases + bundle → adapter → schema/DTO → route →90tests. Never the other way round: the adapter before the port produces a Prisma-shaped port.9192## References9394Each line states **when** to read it. Do not load them all at once.9596### Core — language-agnostic9798- **[references/core/01-layers.md](references/core/01-layers.md)** — The three layers, the dependency direction, the composition root and the directory structure. **Always read it** before creating a new file, to know where it goes.99- **[references/core/02-result-pattern.md](references/core/02-result-pattern.md)** — The `Result` type, the propagation idiom and the three sanctioned exceptions to no-throw. **Always read it** before writing any use case or adapter.100- **[references/core/03-error-catalog.md](references/core/03-error-catalog.md)** — Closed catalog of codes, per-aggregate factories, messages as a wire contract. **Read it** when defining new errors or when you see a per-feature error `enum`.101- **[references/core/04-use-cases.md](references/core/04-use-cases.md)** — Factory-returning-function, `Deps`/`Input`, per-slice bundle and its surface as a security decision. **Read it** on every `feature <name>`.102- **[references/core/05-ports-adapters.md](references/core/05-ports-adapters.md)** — What a port is, invariants in doc-comments, when to split it, the row→entity seam. **Read it** before touching persistence or any external service.103- **[references/core/06-dto-mapping.md](references/core/06-dto-mapping.md)** — Anatomy of the schema file, `toXDto`/`toXInput`, `present<T>()` and correct PATCH. **Read it** when writing the HTTP layer of a slice.104- **[references/core/07-testing.md](references/core/07-testing.md)** — The port fake with `calls`/`failWith`/`guard`, the `subject()` helper, which layer is tested how. **Read it** before writing the first test of a slice.105- **[references/core/08-boundary-enforcement.md](references/core/08-boundary-enforcement.md)** — The three layers of defence and the mandatory negative test. **Always read it** when scaffolding, and **mandatorily** if you touch the linter config.106107### Stacks — per-language detail108109- **[references/stacks/ts-fastify-prisma.md](references/stacks/ts-fastify-prisma.md)** — The default stack. Read it if the server is TypeScript.110- **[references/stacks/csharp-dotnet.md](references/stacks/csharp-dotnet.md)** — Read it only if the server is .NET.111- **[references/stacks/java-spring.md](references/stacks/java-spring.md)** — Read it only if the server is Spring.112- **[references/stacks/go-chi.md](references/stacks/go-chi.md)** — Read it only if the server is Go.113114### Frontends115116- **[references/frontends/vite-react.md](references/frontends/vite-react.md)** — Default SPA.117- **[references/frontends/nextjs.md](references/frontends/nextjs.md)** — If there is SSR/RSC.118- **[references/frontends/tanstack-start.md](references/frontends/tanstack-start.md)** — If full-stack type-safe routing was requested.119120### Operations121122- **[references/ops/deployment.md](references/ops/deployment.md)** — Containers, single proxy, monorepo build context. Read it when preparing the deployment.123- **[references/ops/quality-gates.md](references/ops/quality-gates.md)** — `health.sh`, CI, per-workspace script coverage. Read it when scaffolding and when auditing.124- **[references/ops/config-env.md](references/ops/config-env.md)** — Variables by trust boundary, environment validation, secret leakage into the bundle. Read it before adding any variable.125- **[references/ops/agent-tooling.md](references/ops/agent-tooling.md)** — ahk, autoskills, and why you sometimes have to restart the session. Read it at the phase gate.126127### Cross-cutting128129- **[references/decisions.md](references/decisions.md)** — The ~12 interview decisions with their trade-off. Read it in interview mode or when someone questions a default.130- **[references/audit-checklist.md](references/audit-checklist.md)** — Actionable checklist with concrete commands. Read it in `audit` mode.131132## Scripts133134| Script | What for |135|---|---|136| `node scripts/scaffold.mjs <preset>` | Generates the preset tree from `templates/` |137| `node scripts/new-feature.mjs <name>` | New slice across the three layers + tests |138| `node scripts/check-boundaries.mjs` | **Negative test**: injects a forbidden import and requires the lint to fail |139| `node scripts/check-env-secrets.mjs` | Detects privileged credentials exposed to the client bundle |140| `node scripts/check-coverage.mjs` | Verifies that every workspace declares `typecheck`/`build`/`test`/`lint` or a documented exemption |141| `node scripts/bootstrap-tooling.mjs` | ahk init/build + autoskills, with a fallback |142143Templates in `templates/_root/`, `templates/packages/`, `templates/apps/`,144`templates/deploy/`, `templates/feature/`.145146## Delegation: library versions and APIs147148**There is no version knowledge embedded in this skill, and you must not add any.**149For the current API, configuration or syntax of Fastify, Prisma, Zod, React, Vite,150EF Core, Spring or any other dependency, consult **Context7 MCP**151(`resolve-library-id` → `query-docs`) before writing the code. The references in152`references/core/` describe the *pattern*, which does not expire; versions do.