A Claude Code plugin that enforces hexagonal architecture (ports & adapters) in Symfony projects. Works with both new projects (full scaffolding) and existing projects (progressive, module-by-module refactoring).
FAQ
symfony-hexagonal-skill is a Claude Code plugin with 10 hand-picked skills for development work, indexed on Flowy. Install it with the command on its page. It includes symfony-api-response, symfony-cqrs-handlers, symfony-doctrine-persistence. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
$ npx -y skills add aligundogdu/symfony-hexagonal-skill --agent claude-code
A Claude Code plugin that enforces hexagonal architecture (ports & adapters) in Symfony projects. Works with both new projects (full scaffolding) and existing projects (progressive, module-by-module refactoring).
No slash commands needed โ skills and agents activate automatically based on conversation context.
Copy the skills, agents, and architecture rules into your Symfony project's .claude/ directory:
# Clone the repository
git clone https://github.com/aligundogdu/symfony-hexagonal-skill.git /tmp/hex-skill
# Create the required directories in your project
mkdir -p your-project/.claude/skills your-project/.claude/agents
# Copy skills and agents
cp -r /tmp/hex-skill/skills/* your-project/.claude/skills/
cp -r /tmp/hex-skill/agents/* your-project/.claude/agents/
# Add architecture rules to your project's CLAUDE.md
cat /tmp/hex-skill/CLAUDE.md >> your-project/CLAUDE.md
# Clean up
rm -rf /tmp/hex-skill
You can commit the .claude/skills/ and .claude/agents/ directories so the entire team shares the same rules, or add them to .gitignore to keep it local.
If you want to use the plugin across multiple projects without copying:
# Clone once
git clone https://github.com/aligundogdu/symfony-hexagonal-skill.git ~/symfony-hexagonal-skill
# In each Symfony project, symlink the skills and agents
mkdir -p .claude
ln -s ~/symfony-hexagonal-skill/skills .claude/skills
ln -s ~/symfony-hexagonal-skill/agents .claude/agents
# Copy CLAUDE.md rules into your project (merge manually if you already have one)
cp ~/symfony-hexagonal-skill/CLAUDE.md ./CLAUDE.md
After installation, start Claude Code in your project directory and ask:
> Analyze the project structure for hexagonal architecture compliance
If installed correctly, the hexagonal-architect agent will scan your project and return a compliance report. Skills activate automatically based on conversation context - no slash commands needed.
When starting a Symfony project from scratch, the plugin will set up the full hexagonal structure for you.
> Create a new Symfony project with hexagonal architecture for an e-commerce platform
The plugin will generate the base directory structure across all four layers (Domain, Application, Infrastructure, Presentation) and configure services.yaml with proper port-to-adapter bindings.
> Create a Product module with name, price, and category
This generates:
services.yamlEvery new module, feature, and endpoint follows the same hexagonal rules automatically. The plugin validates each piece of code it generates against the Core Rules before outputting it.
This is where the plugin truly shines. Most Symfony projects already have code โ traditional MVC controllers, Doctrine entities with annotations, services calling repositories directly. You don't have to rewrite everything.
> Add a "featured" flag to the Product entity with an API endpoint to toggle it
The Product module is currently using traditional Symfony structure
(Entity/ with Doctrine annotations, a ProductRepository extending
ServiceEntityRepository, and a ProductController with business logic).
I can proceed in one of three ways:
1. Refactor first โ Migrate the Product module to hexagonal architecture,
then add the featured flag
2. Hexagonal for new code only โ Add the featured flag using hexagonal
patterns (Command/Handler, port interface) while leaving existing
Product code as-is
3. Keep current structure โ Add the featured flag in the existing
traditional style
Which do you prefer?
You pick the option that fits your timeline and risk tolerance. The plugin respects your choice and remembers it for the session.
Progressive refactoring is the plugin's strategy for migrating existing projects to hexagonal architecture without big-bang rewrites.
| Big-Bang Rewrite | Progressive Refactoring |
|---|---|
| Weeks of work before any value | Value from day one |
| High risk โ everything changes at once | Low risk โ one module at a time |
| Blocks feature development | Happens alongside feature development |
| Merge conflicts across the team | Minimal disruption to other developers |
| All-or-nothing commitment | Try it on one module, expand if you like it |
The plugin follows a simple principle: refactor what you touch, leave the rest alone.
When you choose to refactor a module, the migration happens in a specific order:
Step 1: Domain Layer
โโ Extract entities (remove Doctrine annotations)
โโ Create value objects (replace primitive types)
โโ Define port interfaces (repository, external services)
โโ Add domain events
Step 2: Application Layer
โโ Create Commands and Queries (from controller logic)
โโ Create Handlers (move business logic here)
โโ Create DTOs (for input/output boundaries)
Step 3: Infrastructure Layer
โโ Move Doctrine mapping to XML/separate config
โโ Create repository adapters (implement port interfaces)
โโ Bind ports to adapters in services.yaml
Step 4: Presentation Layer
โโ Thin out controllers (dispatch commands/queries only)
โโ Apply standard JSON response format
โโ Add #[IsGranted] to every endpoint
Each step results in working code. You can stop after any step and continue later.
It's perfectly fine to have some modules in hexagonal architecture and others in traditional Symfony. The plugin handles this gracefully:
The plugin enforces 4 non-negotiable rules for all hexagonal code:
The Domain layer has zero external dependencies. No Symfony imports, no Doctrine imports, no third-party libraries. Only pure PHP.
Allowed direction: Presentation โ Application โ Domain โ Infrastructure
Every external interaction (database, API, filesystem, email) goes through a port interface defined in Domain/{Module}/Port/. Concrete implementations live in Infrastructure/.
Write operations use Commands (return void or ID). Read operations use Queries (return DTOs). Each has a dedicated handler. Two separate buses: command.bus and query.bus.
Side-effects (sending emails, updating caches, notifying systems) are triggered through domain events, never called directly from command handlers.
{result, error, extra, status} with debug mode#[IsGranted] or a Voter$this->addSql()Each module follows this layout under src/:
src/
โโโ Domain/{Module}/
โ โโโ Entity/ # Aggregate roots, entities (pure PHP)
โ โโโ ValueObject/ # Immutable, self-validating value objects
โ โโโ Event/ # Domain events (past-tense naming)
โ โโโ Exception/ # Domain-specific exceptions
โ โโโ Port/ # Interfaces for external dependencies
โ
โโโ Application/{Module}/
โ โโโ Command/ # Write operation DTOs + Handlers
โ โโโ Query/ # Read operation DTOs + Handlers
โ โโโ DTO/ # Data transfer objects
โ โโโ EventHandler/ # Domain event side-effect handlers
โ
โโโ Infrastructure/{Module}/
โ โโโ Persistence/ # Doctrine repositories + ORM mappings
โ โโโ Messaging/ # Message transport adapters
โ โโโ ExternalService/ # HTTP clients, third-party APIs
โ
โโโ Presentation/{Module}/
โโโ API/ # REST controllers
โโโ CLI/ # Console commands
โโโ GraphQL/ # Resolvers and type definitions
Tests mirror this structure:
tests/
โโโ Unit/Domain/ # Pure PHP tests, no framework
โโโ Integration/Application/ # Handler tests with mocked ports
โโโ Functional/Presentation/ # Full HTTP stack tests
Skills activate automatically based on your conversation context. No slash commands needed.
| Skill | Triggers On | What It Does |
|---|---|---|
| hexagonal-architecture | architecture, module, layer, scaffold, project structure | Project setup, module scaffolding, layer rules |
| domain-modeling | entity, value object, domain event, aggregate | Entity patterns, value objects, domain events |
| cqrs-handlers | command, query, handler, CQRS, use case | Command/Query creation, handler patterns, bus config |
| ports-adapters | port, adapter, interface, DI, autowiring | Port interfaces, adapter implementations, DI binding |
| api-response | API, endpoint, controller, response, REST | JSON payload standard, exception handling |
| messenger-async | messenger, async, queue, retry, scheduler | Async processing, idempotency, Symfony Scheduler |
| security-voters | security, voter, role, authorization | Voter patterns, role hierarchy, access control |
| doctrine-persistence | doctrine, repository, database, mapping, migration | Repository adapters, XML mapping, migration workflow |
| validation | validation, validator, constraint | 3-layer validation (presentation, application, domain) |
| testing | test, PHPUnit, TDD, unit test, mock | Test organization, TDD workflow, in-memory adapters |
Each skill includes reference files with complete code examples, configuration snippets, and patterns ready to use.
| Agent | Model | Purpose |
|---|---|---|
| hexagonal-architect | Sonnet | Analyzes project structure, designs module architecture, produces compliance scores (0-100). Read-only. |
| hexagonal-reviewer | Sonnet | Reviews code changes against all rules. Reports violations as CRITICAL / WARNING / INFO. Read-only. |
Agents are invoked through natural conversation:
> Review my recent changes for hexagonal compliance
> Analyze the project structure and give me a compliance score
> Design the architecture for a Notification module
Both agents are read-only โ they analyze and report but never modify your code.
> Create a User module with registration, login, and profile management
> Add a password reset flow to the User module
> I want to refactor the Order module to hexagonal architecture
> Review the project for hexagonal architecture compliance
> Show me how to create a value object for Money with currency support
> How should I configure Symfony Messenger for async order processing?
> Create a Voter for order authorization โ owner can edit, admin can delete
MIT
.gitignore
agents/
hexagonal-architect.md
hexagonal-reviewer.md
CLAUDE.md
README.md
skills/
symfony-api-response/
references/
exception-handling.md
payload-schema.md
SKILL.md
symfony-cqrs-handlers/
references/
bus-configuration.md
command-patterns.md
query-patterns.md
SKILL.md
symfony-doctrine-persistence/
references/
mapping-patterns.md
migration-workflow.md
no-native-sql.md
repository-patterns.md
SKILL.md
symfony-domain-modeling/
references/
domain-event-patterns.md
entity-patterns.md
value-object-patterns.md
SKILL.md
symfony-hexagonal-architecture/
references/
dependency-rules.md
directory-structure.md
layer-responsibilities.md
SKILL.md
symfony-messenger-async/
references/
idempotency-patterns.md
messenger-config.md
scheduler-patterns.md
SKILL.md
symfony-ports-adapters/
references/
di-configuration.md
port-adapter-examples.md
SKILL.md
symfony-security-voters/
references/
role-hierarchy.md
voter-patterns.md
SKILL.md
symfony-testing/
references/
test-organization.md
test-patterns.md
SKILL.md
symfony-validation/
references/
validation-layers.md
SKILL.mdยฉ 2026 Flowy ยท Free and open source
Built for Claude Code ยท Not affiliated with Anthropic