hexagonal
Skill4 starsChanged 4 months agoMITView on GitHub
Isolate a framework-agnostic domain core behind ports (interfaces) and drive it through adapters at the edges, so the dependency direction always points inward and infrastructure stays swappable. Use when the user wants domain logic that does not import framework, ORM, or HTTP classes so it can be tested and reused in isolation; the user needs to swap a database, message queue, or third-party client without changing business logic; the user wants to unit-test use cases by substituting in-memory fakes for databases and external services. Keywords: hexagonal, ports-and-adapters, architecture, dependency-direction, domain, decoupling.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- G1Joshi/Agent-Skillstheir own version, first seen Oct 13, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- G1Joshi/Agent-Skills★ 15same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository119 other files it gives its agents.
- strategy-bitrix-d7-incrementalSkill
- strategy-explicit-over-magicSkill
- strategy-framework-conventionsSkill
- strategy-legacy-safe-editsSkill
- strategy-minimal-diffSkill
- strategy-no-untested-refactorSkill
- strategy-preserve-public-apiSkill
- strategy-readonly-immutabilitySkill
- strategy-security-firstSkill
- strategy-test-drivenSkill
- openapiSkill
- paginationSkill
- rest-designSkill
- versioningSkill
- cqrsSkill
- dependency-inversionSkill
- repository-patternSkill
- service-layerSkill
- bitrixSkill
- findings-reportSkill
- laravelSkill
- performanceSkill
- phpSkill
- project-analysisSkill
- refactoringSkill
- roi-prioritizationSkill
- securitySkill
- stack-detectionSkill
- cache-layersSkill
- component-engineSkill
- d7-eventsSkill
- d7-loaderSkill
- d7-orm-queriesSkill
- iblock-elementsSkill
- kernel-main-moduleSkill
- localizationSkill
- controllersSkill
- ormSkill
- validationSkill
- controllersSkill
- query-builderSkill
- routingSkill
- autoload-psr4Skill
- dependency-managementSkill
- scriptsSkill
- connection-poolingSkill
- mysql-indexingSkill
- redisSkill
- transactionsSkill
- ci-github-actionsSkill
- deployment-strategiesSkill
- docker-phpSkill
- env-configSkill
- associationsSkill
- entities-mappingSkill
- orm-basicsSkill
- entity-apiSkill
- module-developmentSkill
- routing-controllersSkill
- formsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 4 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 65
Do not force a hexagonal core when the team deliberately builds framework-native (active-record, controllers-with-logic) and accepts the …
- Distinctive: line 66
Do not impose ports and adapters on a thin CRUD script that has no business rules and will never swap infrastructure.
- Very specific: line 79
Write a concrete adapter in the infrastructure layer that implements the port, e.g.
- Distinctive: line 89
Keep framework, ORM, and transport types (requests, Eloquent models, HTTP clients) out of the domain.
- Distinctive: line 125
Not applicable — no I/O, auth, or untrusted input.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- generated: do not edit — source: knowledge/atoms/architecture/hexagonal/ --><!-- schema: atomVersion=3 skillVersion=2 graphVersion=1 --><!-- compile: @php-skills/compiler v1.0.0 (deterministic build) -->Hexagonal Architecture (Ports & Adapters)
When to use
- The user wants domain logic that does not import framework, ORM, or HTTP classes so it can be tested and reused in isolation.
- The user needs to swap a database, message queue, or third-party client without changing business logic.
- The user wants to unit-test use cases by substituting in-memory fakes for databases and external services.
When NOT to use
- Do not force a hexagonal core when the team deliberately builds framework-native (active-record, controllers-with-logic) and accepts the coupling.
- Do not impose ports and adapters on a thin CRUD script that has no business rules and will never swap infrastructure.
Core guidance
- Express ports as interfaces owned by the core — Declare each port as an interface that lives with the domain, and let adapters in the infrastructure layer implement it.
- Point every dependency toward the core — Let the domain core depend on nothing outward; adapters and framework code depend on the core's ports, never the reverse.
Quick recipe
- Declare a driven port interface in the domain for each outbound need, e.g.
interface OrderRepositorywithsave(Order $order): void, typed only in domain terms. (verify: The interface lives with the domain and references no framework or ORM type) - Write a concrete adapter in the infrastructure layer that implements the port, e.g.
EloquentOrderRepository implements OrderRepository, mapping domain objects to rows. (verify: The adapter satisfies the interface and no domain class references the adapter) - In the composition root, bind the port to the adapter (e.g.
$container->bind(OrderRepository::class, EloquentOrderRepository::class)) and inject the port into the core. (verify: Swapping the binding to an in-memory adapter runs the core unchanged)
Best practices
- Split ports into driving (inbound, called by controllers and CLI to invoke the core) and driven (outbound, implemented by persistence and clients the core calls)
- Keep framework, ORM, and transport types (requests, Eloquent models, HTTP clients) out of the domain; translate them to plain domain objects in the adapter
- Bind each port to a concrete adapter in one composition root (the container config or bootstrap), never by having the core reach for a concrete class
Anti-patterns
| Anti-pattern | Why it fails | Do instead |
| Adapters calling other adapters directly | Adapter-to-adapter calls route business flow around the domain, so logic and ordering rules escape the core and become untestable. | Route every cross-boundary flow through a driving port on the core, so the domain<br>orchestrates the driven adapters. |
| Core code importing the framework directly | A core that reaches for framework classes reverses the dependency direction and can no longer be tested or reused in isolation. | Depend on a port interface owned by the core and inject the framework-backed adapter from<br>the composition root. |
| A separate port for every single method | Over-fragmenting ports multiplies interfaces and wiring without improving cohesion, drowning the design in boilerplate. | Group operations that change together onto one cohesive port named for the capability it<br>provides, splitting only when responsibilities genuinely diverge. |
See references/anti-patterns.md.
Common mistakes
- Ports with an anemic core behind them — Wrapping getters and setters in ports while the real logic lives in adapters produces the ceremony of hexagonal with none of its benefit. Fix: Put the actual business rules in the domain core so the ports guard meaningful behavior, not a pass-through data holder.
- Leaking infrastructure types through a port — Declaring a port method that returns or accepts a framework type (an Eloquent model, a PSR request) drags infrastructure back into the core. Fix: Type ports only in domain terms — entities, value objects, and DTOs the core owns — and map to and from framework types inside the adapter.
- Sharing one persistence model as the domain model — Reusing the ORM entity as the domain entity ties the core's shape to the database schema and its lazy-loading behavior. Fix: Keep a plain domain model and translate it to and from the persistence model inside the driven adapter, even when the two look similar today.
Version notes
- Pure domain modeling with PHP 8.1 features (PHP >=8.1) — PHP 8.1 enums, readonly properties, and first-class enum interfaces let the domain core express value objects and state without any framework dependency.
- Property hooks refine adapter mapping in PHP 8.4 (PHP >=8.4) — From PHP 8.4, property hooks let an adapter expose a domain-shaped view over stored data without a hand-written getter, keeping the mapping code in the adapter thin.
Security
- Not applicable — no I/O, auth, or untrusted input.
Testing
- Activation and decision behavior are verified in
eval/scenarios/architecture/hexagonal.yaml.
Additional resources
- references/anti-patterns.md
- references/core.md
- references/examples.md
- references/pitfalls.md
- references/recipes.md
- references/version-differences.md
Knowledge graph
Related: architecture/cqrs, architecture/dependency-inversion, php/value-objects
<!-- graph-fragment: graph/fragments/architecture/hexagonal.yaml -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

