A lightweight, opinionated framework for AI-assisted backend development with a clear separation of concerns: design first, build with TDD, review before commit.
AI-assisted coding has a known failure mode: a single agent does too many things at once β designs, implements, tests, and reviews β and the result is plausible code that misses the architecture you actually wanted.
This framework solves it by splitting the work across three personas running in sequence, coordinated by five slash commands in Cursor:
| Persona | Command | Job |
|---|---|---|
| π§ Architect | /design |
Translates intent into a four-file spec, decomposed by layer |
| π Developer | /build |
Implements ONE mini-spec with TDD, then stops |
| π Reviewer | /review |
Audits the implementation, approves or returns a diff |
| π§ͺ (utility) | /test |
Runs test suites independently |
| β¨ (utility) | /refactor |
Quality pass: phpcs + phpstan |
Each persona is enforced via a dedicated SKILL.md and is forbidden
from doing the other personas' work. The architect doesn't write code.
The developer doesn't auto-advance. The reviewer doesn't fix code, only
flags. That separation is what makes the loop converge instead of drift.
# 1. Apply the framework to your project
npx degit [sdd-cursor/symfony-php/template](https://github.com/PortilloDev/spec-driven-development-framework/cursor/template/symfony) .cursor
# 2. Personalize stack and conventions (pending implement)
bash .cursor/bootstrap.sh
# 3. In Cursor, design your first feature
/design my-first-feature
# 4. Implement layer by layer
/build @.cursor/specs/my-first-feature/tasks/01-domain.md
/review
# 5. Repeat for each layer
/build @.cursor/specs/my-first-feature/tasks/02-application.md
/review
# ...| Stack | Path | Status |
|---|---|---|
| Symfony 6.4 / PHP 8.3 + Hexagonal + CQRS | symfony-php/template |
β Stable |
| FastAPI / Python 3.11 + Hexagonal | fastapi-py/template |
π§ In progress |
| Laravel 11 + Modular Monolith | laravel-php/template |
π Planned |
Pick the variant that matches your project. The workflow is identical across stacks; only the rules and skill knowledge change.
After running degit and bootstrap.sh, your project has:
.cursor/
βββ README.md # Local guide for your team
βββ commands/
β βββ design.md # Slash command: /design
β βββ build.md # Slash command: /build
β βββ review.md # Slash command: /review
β βββ test.md # Slash command: /test
β βββ refactor.md # Slash command: /refactor
βββ rules/
β βββ workflow.mdc # Loaded always β pipeline reference
β βββ backend-standards.mdc # Loaded always β architectural contract
β βββ stack.mdc # Loaded always β tech stack & tooling
βββ skills/
β βββ architect/SKILL.md # Persona: design without coding
β βββ developer/SKILL.md # Persona: TDD-driven, single task
β βββ senior-reviewer/SKILL.md # Persona: audit, never modify
βββ specs/
βββ template/ # Spec scaffolding used by /design
Plus a bootstrap.sh that asks you a few questions and tailors the rules
to your project (project name, languages, async transport, etc.).
βββββββββββββββββββββββββββ β /design feature β β (architect persona) β ββββββββββββββ¬βββββββββββββ β βΌ .cursor/specs/feature-name/ βββ 00-global-spec.md What & Why βββ 00-technical-plan.md How βββ tasks/ β βββ 01-domain.md β€ 2h, single commit β βββ 02-application.md β€ 2h, single commit β βββ 03-infrastructure.md β€ 2h, single commit β βββ 04-integration.md β€ 2h, single commit βββ status.md Progress tracker
β
βΌ
βββββββββββββββββββββββββββ
β /build {task-file} β
β (developer persona) β
β red β green β
β run tests β
β stop β
ββββββββββββββ¬βββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β /review β
β (reviewer persona) β
β run gates β
β decide β
ββββββββββββββ¬βββββββββββββ
β
βββββββββββββββ΄ββββββββββββββ
βΌ βΌ
APPROVED CHANGES REQUESTED
next task /build same task
(fixing only flagged issues)
---
Large specs cause hallucinations. Each feature is split into single-commit, β€ 2h, single-layer mini-specs. The architect cannot emit a task larger than that β it has to split.
The skills don't suggest what each persona should do β they enforce it with explicit "NEVER" rules. The developer cannot pick the next task. The reviewer cannot edit code. This is the discipline that makes the loop work.
Every public class/method is born from a failing test. /build will
refuse to mark a task as "ready for review" if any test is red. This
isn't dogma β it's the only way to verify the spec was implemented and
not approximated.
backend-standards.mdc is the source of truth for layer rules, naming,
CQRS contracts. The reviewer enforces it line by line. If you want
to change the contract, you change the .mdc β never the code.
alwaysApply: true rules stay short (~150 lines combined). Detail
lives in skill files (SKILL.md) that load only when invoked. This
keeps every conversation's context window for actual work, not boilerplate.
| Tool | Approach | Best for |
|---|---|---|
| OpenSpec | Generic spec format with CLI lifecycle | Multi-tool teams, language-agnostic |
| Spec-Kit / Kiro | Heavy upfront design, full plan before code | Greenfield projects with stable scope |
| BMAD-METHOD | Multi-agent simulation in Cursor | Teams comfortable with agent orchestration |
| SDD Cursor (this) | Three-persona pipeline, TDD-enforced, stack-specific | Brownfield + greenfield, opinionated stacks, solo or small teams |
The differentiator is opinionatedness: SDD Cursor knows your stack (Symfony+CQRS, FastAPI+Hexagonal, etc.) and bakes that knowledge into the skills. Generic tools can't do that without configuration.
β Good fit:
- Projects with a clear architectural contract (Hexagonal, Clean, DDD)
- Backend work where layer separation matters
- Brownfield codebases where consistency is more valuable than speed
- Solo developers or small teams using Cursor as primary IDE
- Stacks where one of the variants applies
- One-shot scripts or throwaway prototypes
- Frontend-heavy projects (this framework is backend-shaped)
- Teams using Claude Code or Aider as primary tool (the slash commands are Cursor-specific)
- Projects where you want the AI to make architectural decisions autonomously
The framework is meant to be a starting point, not a cage. Common customizations:
Drop a new file in .cursor/rules/:
---
description: Project-specific business rules
alwaysApply: true
---
# {Your Project} business rules
- All money values stored as integer cents
- Audit log mandatory on entity mutation
- ...Edit .cursor/skills/{persona}/SKILL.md directly. The framework's
defaults are guidelines; if your team has a stricter review checklist,
add it to the senior-reviewer skill.
Default mini-specs are 01-domain, 02-application, 03-infrastructure,
04-integration. If your stack has more layers (e.g. 02b-events.md
for event handlers), the architect already supports splitting β just
mention it in your /design request.
To pull updates from upstream:
# Backup your local customizations
cp -r .cursor .cursor.bak
# Apply the new version
npx degit ivan-rdz/sdd-cursor#v1.2.0/symfony-php/template .cursor --force
# Diff and merge your customizations back in
diff -ruN .cursor.bak .cursorOr pin to a tag and update intentionally:
npx degit ivan-rdz/sdd-cursor#v1.2.0/symfony-php/template .cursorWhy not OpenSpec or Spec-Kit? Both are excellent, but generic. After using OpenSpec on a Symfony+CQRS project, the generated code consistently missed our naming conventions, async patterns, and domain event recording. Generic spec formats can't encode stack-specific contracts. This framework can β at the cost of being narrower in scope.
Why personas instead of one big prompt?
A single prompt with "be an architect, then a developer, then a reviewer"
collapses into the strongest of the three. Separate skill files with
explicit NEVER rules don't. The model literally has different behavior
when each skill is loaded as the active persona.
Does this work in Claude Code or Aider?
The slash commands are Cursor-specific. The skills (SKILL.md format)
are compatible with Claude Code. With minor adaptations the rules and
skills can be reused; the commands need to be re-expressed as Claude
Code slash commands or Aider scripts. PRs welcome.
Can I use this for frontend?
The framework is shaped for backend work (layers, CQRS, repositories).
Frontend has different decomposition axes (component, store, route).
A react-ts/template variant is on the roadmap but not started.
Is this production-tested? It's used daily on a Symfony 6.4 + Doctrine codebase with ~26k LOC of monthly batch processing, plus a couple of greenfield projects. That's not "battle-tested at scale" but it's not a weekend prototype either.
- FastAPI / Python variant (
fastapi-py/template) - Laravel 11 variant (
laravel-php/template) - Pre-commit hook to validate
status.mdagainst actual test results - CLI replacement for
bootstrap.shwith proper interactive prompts - Example feature gallery (
examples/) covering CRUD, async, events - Compatibility layer for Claude Code slash commands
See open issues for the full list.
Contributions welcome, especially:
- New stack variants (open an issue first to align on scope)
- Improvements to the personas (
SKILL.mdfiles) - Real-world example features for
examples/
For larger changes, please open an issue describing the motivation before submitting a PR.
MIT β use it, fork it, ship it.
This framework stands on shoulders:
- OpenSpec β for the spec/changes/archive lifecycle pattern
- Spec-Kit and Kiro β for spec-driven development as a discipline
- BMAD-METHOD β for the multi-agent persona idea
- The Cursor and Claude Code teams β for making slash commands and skills first-class citizens
The opinionated parts (TDD enforcement, layer-by-layer decomposition, strict persona boundaries) come from real-world pain on a Symfony+DDD codebase that taught us what generic frameworks miss.
Made by IvΓ‘n Portillo PΓ©rez β backend developer, podcast host of Artesanos del CΓ³digo, occasionally shipping things that work.