HE

hexagonal-architecture

Guide for structuring applications using Hexagonal architecture and DDD.

Install

mkdir -p .claude/skills/hexagonal-architecture-michalwelna0 && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15204" && unzip -o skill.zip -d .claude/skills/hexagonal-architecture-michalwelna0 && rm skill.zip

Installs to .claude/skills/hexagonal-architecture-michalwelna0

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Hexagonal architecture (ports/adapters) with DDD principles. Use when implementing features, refactoring code, organizing code structure, determining where code should be placed, creating adapters, services, ports, or when questions arise about architectural layers, dependency direction, adapter patterns, or service patterns.
327 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Place code in the correct layer (domain, service, port, adapter, controller).
  • Define new ports or adapters with correct dependency direction.
  • Create or modify adapters, services, or controllers following layer-specific conventions.
  • Review imports and structure to enforce architectural boundaries.
  • Enforce business rules and invariants in domain models.
  • Orchestrate use cases using services.

How it works

The skill defines responsibilities for controllers, domain models, services, ports, and adapters, and specifies dependency rules to maintain architectural boundaries.

Inputs & outputs

You give it
Features, code to refactor, new ports, adapters, services, or controllers.
You get back
Code organized into domain models, services, ports, and adapters with correct dependency direction and architectural boundaries.

When to use hexagonal-architecture

  • Refactoring code into domains and adapters
  • Defining new ports
  • Determining layer responsibilities

About this skill

Hexagonal Architecture + DDD

When to Use

  • You are adding or refactoring features and need to place code in the correct layer (domain/service/port/adapter/controller).
  • You are defining a new port or adapter and want to ensure dependency direction is correct.
  • You are creating or modifying adapters, services, or controllers and need layer-specific conventions.
  • You are reviewing imports/structure to enforce architectural boundaries.

Quick Reference

TopicFileWhen to Use
Project structureproject-structure.mdCanonical directory tree, code location mapping, layer responsibilities, naming conventions

Controllers (Thin Layer)

Controllers are the entry points that connect external inputs to the application. Examples: a FastAPI app, a Click CLI, a Chainlit chat app. Keep them thin:

  • Parse/validate inputs
  • Call shared services
  • Map errors to appropriate responses (e.g., HTTP status codes, CLI exit codes, UI messages)
  • Serialize outputs via model_dump(mode="json") or equivalent
  • No business rules in controllers

For FastAPI-specific conventions, see the fastapi skill. For Click-specific conventions, see the cli-conventions skill.

Domain Models

  • Put business rules/invariants in domain models (shared/src/shared/domain/**)
  • Raise ValueError with clear messages for domain violations
  • Pydantic v2 is the sole allowed third-party dependency in domain models

For DDD building blocks (entities, value objects, aggregates), file organization, and the persistence contract, see the domain-models skill.

Services (Orchestration)

Services are use-case orchestrators in shared/src/shared/services/**. For system health checks (technical, non-business concerns):

  • Put domain models in shared/src/shared/domain/platform_ops/health/
  • Services should aggregate adapter results into a generic SystemHealth (no per-adapter probe logic in services)

Inputs

  • Fixed internal knobs (model IDs, temperatures, limits) live in a nested:
    • @dataclass(frozen=True, slots=True) class Hyperparams: ...
    • with _HP: Final[Hyperparams] = Hyperparams()
  • Controller-controlled parameters should be Pydantic v2 models named *Params (typically in shared/src/shared/domain/**) and passed as params=...
  • Direct inputs (what to act on) are primitive args alongside params (e.g., source_url: str, article_id: UUID)

Outputs

  • Return domain models (Pydantic); let controllers serialize via model_dump(mode="json")
  • If a workflow needs a composite result, prefer a dedicated domain response model over a raw dict

Validation

  • Validate service-level inputs early (bounds, URL format) using shared validators (e.g., validate_url)
  • Domain invariants live in domain models and raise ValueError
  • Do not duplicate the same validation across service + domain layers

Resource Handling

  • If a service receives closeable dependencies, the wiring layer (controller-side DI / setup) must own lifecycle and close them in finally

Ports (Interfaces)

  • Define boundaries as ports (shared/src/shared/ports/**) using typing.Protocol
  • Minimal method surface; no side effects; no external library imports; return domain types
  • Ports MUST be technology-agnostic: folder names describe business capabilities (e.g., ports/database/, ports/llm/), NOT technologies
  • Repository naming conventions:
    • Single item: get_{model}(...) -> Model | None (missing → None)
    • Lists: list_{model}s(..., limit: int | None = None, offset: int = 0) -> list[Model] (missing → [])
    • Prefer one list_* with multiple optional filters over specialized *_by_* methods

Adapters (Implementations)

Adapters live in shared/src/shared/adapters/** and are technology-specific (e.g., adapters/database/postgres/, adapters/llm/). For adapters integrating external components (DB/LLM/HTTP/etc.), expose:

  • async def health_check(self) -> ComponentHealth
  • Use generic health VO models (ComponentHealth, SystemHealth) and put component diagnostics in details (e.g. db-version, base-url)

Validation

  • Validate adapter inputs early and fail fast with ValueError (non-empty strings, bounds, required IDs)
  • Avoid magic numbers: define timeouts/limits/constants at module top

Error Handling

  • Wrap integration failures as RuntimeError with actionable messages
  • Keep original cause via raise ... from e
  • Log failures at error level (no secrets in logs or exceptions)

Resource Cleanup

  • If an adapter owns network/IO resources, implement close() (async if needed)
  • close() should be best-effort: log and continue on cleanup errors
  • The wiring layer (controller-side DI / setup) must always close adapters in finally

Database (Repository) Adapters

Repository adapters follow the thin wrapper pattern:

  • Delegate CRUD operations to generic helpers in {db_engine}_aggregate_crud.py
  • Define TABLE_NAME and STORED_MODEL_NAME constants at module top
  • Validate db connection in __init__
  • Wrap asyncpg.PostgresError as RuntimeError (done in CRUD helpers, not repeated in adapters)
  • Return validated domain models (deserialized via AggregateRoot.from_payload())

Dependency Direction

  • shared/src/shared/domain/** → no dependencies on project code (standard library + Pydantic only)
  • shared/src/shared/services/** and shared/src/shared/ports/** → may depend only on shared/src/shared/domain/**
  • shared/src/shared/adapters/** → may depend on shared/src/shared/domain/**, shared/src/shared/services/**, and shared/src/shared/ports/**
  • Controller directories (e.g., api/, app/, cli/) → may depend on shared/ (domain, services, ports, adapters), but shared/ must not depend on controllers
  • shared/src/shared/adapters/database/{db-engine}/migrations/** and shared/src/shared/config/** → may depend on shared code but must not be imported from domain, services, or ports

Change Workflow Checklists

Adding New External Capability

  1. Add a new Port in shared/src/shared/ports/
  2. Implement an Adapter in shared/src/shared/adapters/.../
  3. Update/create a Service method in shared/src/shared/services/ to orchestrate via ports
  4. Wire the adapter in the controller layer as needed (do not wire inside shared)

Adding Database Read Model / Cross-Aggregate Lookup

  1. Add a QueryPort in shared/src/shared/ports/database/queries/
  2. Implement the adapter in shared/src/shared/adapters/database/.../queries/
  3. Use services to orchestrate; do not expose adapters directly to controllers

Adding a New Aggregate Repository

  1. Create a migration
  2. Add a repository port in shared/src/shared/ports/database/repositories/
  3. Implement a repository adapter — thin wrapper delegating to {db_engine}_aggregate_crud helpers
  4. Wire the adapter in the controller layer

Adding New Domain Rule

  1. Enforce in the domain model (entity/value object) with clear ValueError messages
  2. Add unit tests in shared/tests/ for both valid and invalid cases

Changing Error Message or Validation

  1. Update/extend tests to match the new behavior and message (tests commonly use match=...)

Cross-References

  • Project structure: See project-structure.md for canonical paths, directory tree, and layer responsibilities
  • Domain models: See domain-models skill for DDD building blocks
  • FastAPI: See fastapi skill for API-specific conventions
  • CLI: See cli-conventions skill for Click-specific conventions
  • Python patterns: See python skill for type hints and error handling

When not to use it

  • When the task is not related to architectural layers or dependency direction.
  • When the task is not about organizing code structure.
  • When the task is not about creating adapters, services, or ports.

Limitations

  • Domain models allow Pydantic v2 as the sole allowed third-party dependency.
  • Ports must be technology-agnostic.
  • Adapters must be technology-specific.

How it compares

This skill provides a structured approach to organizing code into distinct layers with clear dependency rules, unlike an unstructured approach that might lead to tangled dependencies.

Compared to similar skills

hexagonal-architecture side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
hexagonal-architecture (this skill)06moNo flagsAdvanced
software-architecture3336moNo flagsIntermediate
codex322moReviewAdvanced
game-development706moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

software-architecture

davila7

Guide for quality focused software architecture. This skill should be used when users want to write code, design architecture, analyze code, in any case that relates to software development.

333868

codex

Lucklyric

Invoke Codex CLI for complex coding tasks requiring high reasoning capabilities. This skill should be invoked when users explicitly mention "Codex", request complex implementation challenges, advanced reasoning, or need high-reasoning model assistance. Automatically triggers on codex-related requests and supports session continuation for iterative development.

32238

game-development

davila7

Game development orchestrator. Routes to platform-specific skills based on project needs.

70195

senior-fullstack

davila7

Comprehensive fullstack development skill for building complete web applications with React, Next.js, Node.js, GraphQL, and PostgreSQL. Includes project scaffolding, code quality analysis, architecture patterns, and complete tech stack guidance. Use when building new projects, analyzing code quality, implementing design patterns, or setting up development workflows.

35110

command-name

anthropics

This skill should be used when the user asks to "create a plugin", "scaffold a plugin", "understand plugin structure", "organize plugin components", "set up plugin.json", "use ${CLAUDE_PLUGIN_ROOT}", "add commands/agents/skills/hooks", "configure auto-discovery", or needs guidance on plugin directory layout, manifest configuration, component organization, file naming conventions, or Claude Code plugin architecture best practices.

697

python-project-structure

wshobson

Python project organization, module architecture, and public API design. Use when setting up new projects, organizing modules, defining public interfaces with __all__, or planning directory layouts.

860

Search skills

Search the agent skills registry