Place code in the right layer and keep dependencies pointing inward, inside a single service. Covers ports and adapters (hexagonal) layering, the dependency rule, SOLID applied at class and service level, anti-corruption layers, framework isolation, and choosing a design pattern only when a named force demands it. Use when writing or reviewing any implementation code, deciding where a class belongs, wiring a dependency, adding a framework annotation to domain code, or when the user says 'architecture', 'layering', 'SOLID', 'coupling', 'hexagonal', 'design pattern', or 'where should this go'. This skill governs structure inside one service — not where services divide (see service-boundaries), not aggregate rules (see domain-modelling), not adapter craft (see infrastructure-adapters).
The point of layering is not tidiness. It is that business rules should be readable, testable, and
changeable without starting a database, a broker, or a web server — and that swapping any of those
should not touch a line of business logic.
One rule generates almost everything else: dependencies point inward, toward the domain.
Config Resolution
Read .msskills/config.yaml in the repo root; look up paths.architecture.
A custom document exists at that path → read its frontmatter mode:
override → use it alone; ignore the defaults below.
overlay (default, or no mode key) → read defaults first, then
apply the custom document's sections on top, matched by exact heading; new sections append.
A path is configured but no file exists there → say which path is missing, then use the defaults.
No config file or no paths.architecture key → use defaults.
.msskills/stack.md exists → express every rule in that stack's idiom: its module system, its
dependency-injection style, its package conventions, its architecture-test tooling.
No project document and no stack profile → use the defaults, and say once that
stack-profile would make the guidance concrete.
Self-Validation Checklist
STOP after generating or reviewing each class, module, or file. Verify every check. Fix failures
before presenting.
LAYER PLACEMENT: Can you name this file's layer — domain, application, adapter,
infrastructure — and does its responsibility match? If it does two layers' jobs (a handler that
contains a business rule, an entity that writes SQL) → split it.
DEPENDENCY DIRECTION: Does every import point inward or sideways within the layer? An inner
layer importing an outer one → invert it with an interface owned by the inner layer.
FRAMEWORK ISOLATION: Is the domain free of framework and library types — annotations, ORM
base classes, HTTP types, broker clients, serialisation attributes? If not → move them to the
adapter and map at the edge.
PORTS OWNED INWARD: Is each outbound interface declared in the layer that uses it, not the
layer that implements it? A repository interface next to its database implementation is not a
port; it is a package split.
SINGLE RESPONSIBILITY: Can you describe this class in one sentence without "and"? If not →
extract. Watch for the common pair: business logic and persistence.
OPEN/CLOSED: Would a new variant of an existing concept require editing a switch in
several files? If yes → introduce polymorphism, but only for a variation that has actually
happened twice.
LISKOV: Does every implementation of an interface honour its contract, or do some throw
UnsupportedOperation, tighten preconditions, or return null where others cannot? If so → the
abstraction is wrong; split it.
INTERFACE SEGREGATION: Does any caller depend on an interface where it uses one of eight
methods? Split by consumer need, not by implementation convenience.
DEPENDENCY INVERSION: Does business logic depend on an abstraction it owns, or on a concrete
client? Constructor-injected, never resolved from a static locator or newed inline.
TESTABLE WITHOUT I/O: Can this class's behaviour be tested without a database, network, or
clock? If not → push the side effect outward and inject time, IDs, and randomness.
PATTERN JUSTIFIED: If a named design pattern appears, can you state the force that demands
it in one sentence? "It is more extensible" is not a force → remove the indirection.
All checks pass → state "Passes clean-architecture. [next step]."
Active Anti-Pattern Scan
Any box you can check is a defect. Fix it before presenting.
Anaemic Domain: entities are field bags and all rules live in services → move the
invariants onto the type that owns them.
Framework in the Domain: ORM, HTTP, or serialisation annotations on domain types → map
at the adapter boundary instead.
Leaky Repository: a port that returns the ORM's query builder, a DataSet, or a
framework page type → return domain types.
Fat Controller: business rules, orchestration, and validation in a handler → the handler
parses input, calls one application service, and renders output.
Service Locator: dependencies fetched from a static container or singleton inside a
method → constructor injection.
Circular Dependency: two modules importing each other → extract the shared concept, or
invert one direction with an interface.
Utility Dumping Ground: a utils, helpers, or common package with unrelated statics →
move each function next to the concept it belongs to.
Speculative Abstraction: an interface with exactly one implementation and no second one in
sight, or a plugin system nobody plugs into → inline it until a real second case appears.
Pattern Theatre: factories producing factories, a strategy with one strategy, an observer
with one observer → delete the indirection.
Leaked External Model: a third-party or upstream DTO used directly as a domain type → add
an anti-corruption layer and translate at the edge.
Hidden Global State: static mutable state, ambient singletons, DateTime.now() buried in
logic → inject it.
Transaction in the Domain: commit or session handling inside domain code → own the
transaction in the application layer.
Ambiguity Signals
Route these through collaborative-judgment. Each has two defensible answers.
How many layers. Full four-layer separation is right for a service with real domain
complexity and ceremony for a CRUD adapter over one table. Propose the lighter shape and let the
user ask for more.
Port granularity. One repository per aggregate is conventional; one narrow port per use case
is more honest about what each caller needs and produces more interfaces. Both defensible.
Mapping cost. Separate domain, persistence, and API models are the clean answer and triple
the type count. Sharing one model is pragmatic until the first field that only one of them needs.
When an abstraction has earned its place. The rule of three is a guideline, not a law; a
second case with the same reason to change can justify it, and three coincidentally similar
cases do not.
Where a rule lives when two aggregates share it. A domain service, a policy object, or
duplication in both — the right answer depends on which one owns the invariant.
1---2name: clean-architecture3description: Place code in the right layer and keep dependencies pointing inward, inside a single service. Covers ports and adapters (hexagonal) layering, the dependency rule, SOLID applied at class and service level, anti-corruption layers, framework isolation, and choosing a design pattern only when a named force demands it. Use when writing or reviewing any implementation code, deciding where a class belongs, wiring a dependency, adding a framework annotation to domain code, or when the user says 'architecture', 'layering', 'SOLID', 'coupling', 'hexagonal', 'design pattern', or 'where should this go'. This skill governs structure inside one service — not where services divide (see service-boundaries), not aggregate rules (see domain-modelling), not adapter craft (see infrastructure-adapters).4license: MIT5---67# Clean Architecture89The point of layering is not tidiness. It is that business rules should be readable, testable, and10changeable without starting a database, a broker, or a web server — and that swapping any of those11should not touch a line of business logic.1213One rule generates almost everything else: **dependencies point inward, toward the domain.**1415## Config Resolution16171. Read `.msskills/config.yaml` in the repo root; look up `paths.architecture`.182. A custom document exists at that path → read its frontmatter `mode`:19 - `override` → use it alone; ignore the defaults below.20 - `overlay` (default, or no `mode` key) → read [defaults](./references/defaults.md) first, then21 apply the custom document's sections on top, matched by exact heading; new sections append.223. A path is configured but no file exists there → say which path is missing, then use the defaults.234. No config file or no `paths.architecture` key → use [defaults](./references/defaults.md).245. `.msskills/stack.md` exists → express every rule in that stack's idiom: its module system, its25 dependency-injection style, its package conventions, its architecture-test tooling.266. No project document and no stack profile → use the defaults, and say once that27 `stack-profile` would make the guidance concrete.2829## Self-Validation Checklist3031**STOP after generating or reviewing each class, module, or file. Verify every check. Fix failures32before presenting.**33341. **LAYER PLACEMENT**: Can you name this file's layer — domain, application, adapter,35 infrastructure — and does its responsibility match? If it does two layers' jobs (a handler that36 contains a business rule, an entity that writes SQL) → split it.372. **DEPENDENCY DIRECTION**: Does every import point inward or sideways within the layer? An inner38 layer importing an outer one → invert it with an interface owned by the inner layer.393. **FRAMEWORK ISOLATION**: Is the domain free of framework and library types — annotations, ORM40 base classes, HTTP types, broker clients, serialisation attributes? If not → move them to the41 adapter and map at the edge.424. **PORTS OWNED INWARD**: Is each outbound interface declared in the layer that *uses* it, not the43 layer that implements it? A repository interface next to its database implementation is not a44 port; it is a package split.455. **SINGLE RESPONSIBILITY**: Can you describe this class in one sentence without "and"? If not →46 extract. Watch for the common pair: business logic *and* persistence.476. **OPEN/CLOSED**: Would a new variant of an existing concept require editing a `switch` in48 several files? If yes → introduce polymorphism, but only for a variation that has actually49 happened twice.507. **LISKOV**: Does every implementation of an interface honour its contract, or do some throw51 `UnsupportedOperation`, tighten preconditions, or return null where others cannot? If so → the52 abstraction is wrong; split it.538. **INTERFACE SEGREGATION**: Does any caller depend on an interface where it uses one of eight54 methods? Split by consumer need, not by implementation convenience.559. **DEPENDENCY INVERSION**: Does business logic depend on an abstraction it owns, or on a concrete56 client? Constructor-injected, never resolved from a static locator or `new`ed inline.5710. **TESTABLE WITHOUT I/O**: Can this class's behaviour be tested without a database, network, or58 clock? If not → push the side effect outward and inject time, IDs, and randomness.5911. **PATTERN JUSTIFIED**: If a named design pattern appears, can you state the force that demands60 it in one sentence? "It is more extensible" is not a force → remove the indirection.6162All checks pass → state "Passes clean-architecture. [next step]."6364## Active Anti-Pattern Scan6566Any box you can check is a defect. Fix it before presenting.6768- [ ] **Anaemic Domain**: entities are field bags and all rules live in services → move the69 invariants onto the type that owns them.70- [ ] **Framework in the Domain**: ORM, HTTP, or serialisation annotations on domain types → map71 at the adapter boundary instead.72- [ ] **Leaky Repository**: a port that returns the ORM's query builder, a `DataSet`, or a73 framework page type → return domain types.74- [ ] **Fat Controller**: business rules, orchestration, and validation in a handler → the handler75 parses input, calls one application service, and renders output.76- [ ] **Service Locator**: dependencies fetched from a static container or singleton inside a77 method → constructor injection.78- [ ] **Circular Dependency**: two modules importing each other → extract the shared concept, or79 invert one direction with an interface.80- [ ] **Utility Dumping Ground**: a `utils`, `helpers`, or `common` package with unrelated statics →81 move each function next to the concept it belongs to.82- [ ] **Speculative Abstraction**: an interface with exactly one implementation and no second one in83 sight, or a plugin system nobody plugs into → inline it until a real second case appears.84- [ ] **Pattern Theatre**: factories producing factories, a strategy with one strategy, an observer85 with one observer → delete the indirection.86- [ ] **Leaked External Model**: a third-party or upstream DTO used directly as a domain type → add87 an anti-corruption layer and translate at the edge.88- [ ] **Hidden Global State**: static mutable state, ambient singletons, `DateTime.now()` buried in89 logic → inject it.90- [ ] **Transaction in the Domain**: commit or session handling inside domain code → own the91 transaction in the application layer.9293## Ambiguity Signals9495Route these through `collaborative-judgment`. Each has two defensible answers.9697- **How many layers.** Full four-layer separation is right for a service with real domain98 complexity and ceremony for a CRUD adapter over one table. Propose the lighter shape and let the99 user ask for more.100- **Port granularity.** One repository per aggregate is conventional; one narrow port per use case101 is more honest about what each caller needs and produces more interfaces. Both defensible.102- **Mapping cost.** Separate domain, persistence, and API models are the clean answer and triple103 the type count. Sharing one model is pragmatic until the first field that only one of them needs.104- **When an abstraction has earned its place.** The rule of three is a guideline, not a law; a105 second case with the same reason to change can justify it, and three coincidentally similar106 cases do not.107- **Where a rule lives when two aggregates share it.** A domain service, a policy object, or108 duplication in both — the right answer depends on which one owns the invariant.
Run npx skillmds@latest add parvez3019/clean-architecture in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Place code in the right layer and keep dependencies pointing inward, inside a single service. Covers ports and adapters (hexagonal) layering, the dependency rule, SOLID applied at class and service level, anti-corruption layers, framework isolation, and choosing a design pattern only when a named force demands it. Use when writing or reviewing any implementation code, deciding where a class belongs, wiring a dependency, adding a framework annotation to domain code, or when the user says 'architecture', 'layering', 'SOLID', 'coupling', 'hexagonal', 'design pattern', or 'where should this go'. This skill governs structure inside one service — not where services divide (see service-boundaries), not aggregate rules (see domain-modelling), not adapter craft (see infrastructure-adapters). It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free. This skill is licensed under MIT.
parvez3019 (@parvez3019) published this skill. Their other Agent Skills are listed on their SkillMD profile.