MidТеория10 min

Интеграция SDD с инструментами

Практическая настройка SDD с Claude Code, Cursor, Copilot и другими инструментами

SDD -- инструмент-агностик

Spec-Driven Development -- это методология, а не продукт. Она работает с любым AI-инструментом, который умеет принимать текстовые инструкции и генерировать код. Но степень интеграции и удобство работы сильно различаются в зависимости от инструмента.

Уровни интеграции SDD:

Уровень 1: Копировать спеку → вставить в чат AI
           (работает с любым AI)

Уровень 2: AI читает спеку из файловой системы
           (Claude Code, Cursor, Windsurf)

Уровень 3: AI использует спеку как контекст между сессиями
           (Claude Code с Memory, AGENTS.md)

Уровень 4: CI/CD валидирует спеку автоматически
           (любой CI + OpenAPI/JSON Schema)

В этой статье рассмотрим практическую настройку SDD для основных AI-инструментов разработки.


Claude Code

Claude Code -- это терминальный AI-агент от Anthropic. Он работает непосредственно в файловой системе проекта и может читать, создавать и модифицировать файлы. Это делает его идеальным инструментом для SDD.

CLAUDE.md как контекст проекта

Файл CLAUDE.md в корне проекта -- это первое, что Claude Code читает при запуске. Он задаёт контекст: архитектуру, конвенции, запрещённые паттерны.

# CLAUDE.md

## Project: IT Crib Learning Platform

### Architecture
- Backend: Symfony 7.4 + PHP 8.4 (api/)
- Frontend: Nuxt 3 SPA (app/)
- DB: PostgreSQL 18
- Cache: Redis 7
- Search: Meilisearch
- Queue: RabbitMQ via Symfony Messenger

### Conventions
- PHP: final classes, strict_types, constructor promotion
- All IDs: UUID v7
- All tables: created_at/updated_at TIMESTAMPTZ
- Pagination: keyset only (no OFFSET)
- Tests: PHPUnit 11, PHPStan level 9

### Specs Directory
All feature specifications are in specs/ directory.
Before implementing any feature, check if a spec exists.
If no spec exists, create one first.

### Forbidden Patterns
- No raw SQL (use Doctrine QueryBuilder)
- No service locator (constructor injection only)
- No hard deletes (soft delete with deleted_at)
- No OFFSET pagination
- No @phpstan-ignore annotations

Использование спецификаций с Claude Code

Спецификации хранятся в проекте и Claude Code читает их как обычные файлы.

# Start Claude Code in project root
claude

# Ask Claude to read the spec first
> Read specs/features/user-registration.md and implement
  Task 4.1: RegistrationService according to the specification.
  Follow all conventions from CLAUDE.md.

Claude Code автоматически:

  1. Прочитает CLAUDE.md для контекста проекта
  2. Прочитает указанную спецификацию
  3. Проверит существующие файлы проекта
  4. Сгенерирует код, соответствующий спеке и конвенциям
  5. Может запустить тесты и линтер для верификации

Агентный режим для автономной реализации

В агентном режиме Claude Code может выполнять полную фазу Implement автономно.

# Autonomous implementation of a task
> Implement all tasks from specs/features/rate-limiting.md
  For each task:
  1. Create the necessary files
  2. Run PHPStan to verify
  3. Run related tests
  4. Report status before moving to next task

  Stop and ask me if:
  - A task fails after 3 attempts
  - You need to modify the spec
  - You encounter an architectural decision

Memory для эволюции спецификаций

Claude Code с MCP Memory сохраняет знания между сессиями. Это позволяет спецификациям эволюционировать.

## Workflow с Memory

Сессия 1: Написали спеку для регистрации
  → memory_save: "User registration spec completed, stored in specs/features/"

Сессия 2: Реализация показала gap в спеке
  → memory_save: "Registration spec updated: added re-registration
    flow for pending users. Pattern: always handle existing entity states."

Сессия 3: Новая фича использует те же паттерны
  → memory_recall: "registration spec patterns"
  → AI знает про re-registration pattern и применяет его
Что сохранять Пример Зачем
Spec gaps "Spec didn't cover blocked users re-registration" Улучшить шаблоны
Conventions discovered "DTO validation via Symfony attributes works better" Стандартизировать
AI failure patterns "AI generates raw SQL when not reminded about QueryBuilder" Предотвратить
Successful patterns "State machine spec produced 100% first-attempt success" Повторить

Cursor

Cursor -- это fork VS Code с встроенным AI. Его отличие -- глубокая интеграция с кодовой базой: AI "видит" весь проект и может работать с несколькими файлами одновременно.

.cursorrules для конвенций проекта

Файл .cursorrules в корне проекта -- аналог CLAUDE.md для Cursor. Он задаёт правила, которые AI должен соблюдать.

# .cursorrules

## PHP Conventions
- Always use declare(strict_types=1)
- Classes are final by default
- Use constructor property promotion
- All parameters and return types must have type hints
- Use readonly for DTOs and Value Objects

## Database Conventions
- UUID v7 for all primary keys
- Always include created_at/updated_at TIMESTAMPTZ
- Keyset pagination only (no OFFSET)
- Index all foreign keys
- CREATE INDEX CONCURRENTLY in migrations

## Testing Conventions
- PHPUnit 11 with attributes (#[Test], #[DataProvider])
- PHPStan level 9
- Integration tests extend WebTestCase
- Test method names describe behavior

## Architecture
- Thin controllers: validate input, call service, return response
- Services contain business logic
- Repositories contain data access logic
- Async operations via Messenger (RabbitMQ)

## Forbidden
- No raw SQL queries
- No service locator pattern
- No @phpstan-ignore annotations
- No hard deletes of user data
- No OFFSET pagination

Composer для мульти-файловой реализации

Cursor Composer позволяет AI работать с несколькими файлами одновременно -- идеально для реализации задач из спецификации.

Composer prompt:

@specs/features/user-registration.md

Implement Task 4.1 (RegistrationService) from this specification.

Create these files:
1. src/Service/RegistrationService.php
2. src/Exception/EmailAlreadyExistsException.php

Use existing files for context:
- src/Repository/UserRepository.php
- src/Entity/User.php
- src/Entity/ConfirmationToken.php

@docs для ссылок на спецификации

Cursor позволяет ссылаться на файлы прямо в чате с помощью @.

Chat prompt:

Looking at @specs/api/openapi.yaml, generate the RegistrationController
that handles POST /api/v1/auth/register endpoint.

Also check @src/Service/RegistrationService.php for the service interface
that the controller should call.

GitHub Copilot

GitHub Copilot работает иначе -- это прежде всего инструмент автодополнения и чата внутри IDE. Он не имеет агентного режима (на момент написания), но всё равно можно интегрировать SDD.

.github/copilot-instructions.md

GitHub Copilot поддерживает файл инструкций на уровне репозитория.

# .github/copilot-instructions.md

## Project Context
This is a PHP 8.4 / Symfony 7.4 learning platform.
Feature specifications are stored in specs/ directory.

## Code Style
- Always declare(strict_types=1)
- Final classes by default
- Constructor property promotion
- Full type hints everywhere
- PHPStan level 9 compatible

## Patterns
- Thin controllers (validate → service → response)
- Services for business logic
- Repositories for data access
- Async via Symfony Messenger

## Never Do
- Raw SQL queries (use Doctrine)
- Service locator pattern
- @phpstan-ignore annotations
- OFFSET pagination (use keyset)

Copilot Chat со спецификациями

Copilot Chat:

/file specs/features/user-registration.md

Based on this specification, implement the RegistrationService.
Focus on the register() method described in Task 4.1.

Copilot CLI для исполнения задач

GitHub Copilot CLI может помочь с отдельными командами в рамках SDD.

# Ask Copilot for a command to verify implementation
gh copilot suggest "run phpstan on RegistrationService"
# → docker compose exec php vendor/bin/phpstan analyse src/Service/RegistrationService.php --level=9

# Ask for test command
gh copilot suggest "run phpunit tests for registration"
# → docker compose exec php vendor/bin/phpunit --filter=Registration

Стандарт AGENTS.md

Универсальный файл контекста

AGENTS.md -- это формирующийся стандарт для предоставления контекста AI-инструментам. Он не привязан к конкретному инструменту (как CLAUDE.md к Claude Code или .cursorrules к Cursor). Идея: один файл, который работает везде.

# AGENTS.md

## Project Overview
IT Crib — educational platform for developers.
6 sections, 100+ topics, 500+ articles, quizzes, code challenges.

## Technology Stack
- **Backend**: PHP 8.4 / Symfony 7.4
- **Frontend**: Vue 3.6 / Nuxt 4 with TypeScript
- **Database**: PostgreSQL 18
- **Cache**: Redis 7
- **Search**: Meilisearch
- **Queue**: RabbitMQ via Symfony Messenger
- **Container**: Docker Compose v2

## Project Structure

api/ # Symfony backend ├── src/ │ ├── Controller/ # Thin HTTP controllers │ ├── Entity/ # Doctrine entities │ ├── Repository/ # Data access layer │ ├── Service/ # Business logic │ ├── Message/ # Async message DTOs │ └── MessageHandler/ # Async message processors ├── tests/ │ ├── Unit/ │ └── Integration/ └── specs/ # Feature specifications ├── features/ # Feature specs ├── api/ # OpenAPI specs └── templates/ # Spec templates

app/ # Nuxt frontend ├── components/ ├── composables/ ├── pages/ └── stores/


## Conventions
### PHP
- `declare(strict_types=1)` always
- `final` classes by default
- Constructor property promotion
- Type hints on ALL parameters and returns
- `readonly` for DTOs and Value Objects

### Database
- UUID v7 for primary keys
- `created_at`/`updated_at` TIMESTAMPTZ
- Keyset pagination (no OFFSET)
- `CREATE INDEX CONCURRENTLY`

### Testing
- PHPUnit 11 with attributes
- PHPStan level 9
- Integration tests: WebTestCase

## Forbidden Patterns
- Raw SQL queries (use Doctrine QueryBuilder)
- Service locator (use constructor injection)
- @phpstan-ignore annotations
- OFFSET pagination
- Hard deletes of user data
- Storing secrets in code

## Specification-Driven Development
This project uses SDD. Before implementing any feature:
1. Check specs/ for existing specification
2. If none exists, create one using specs/templates/
3. Follow the 4-phase process: Specify → Plan → Tasks → Implement
4. All specs are reviewed before implementation begins

Связь AGENTS.md и спецификаций

AGENTS.md -- это постоянный контекст проекта. Спецификации -- это временные контексты отдельных фич. Вместе они дают AI полную картину.

AGENTS.md (постоянный)
├── Архитектура проекта
├── Конвенции кода
├── Запрещённые паттерны
└── Ссылка на specs/ директорию

specs/ (временные)
├── features/user-registration.md (текущая фича)
├── features/order-system.md (следующая фича)
└── templates/feature-spec-template.md (шаблон)

Version control для спецификаций

Спецификации -- часть кода

Спецификации живут в репозитории наравне с кодом. Они версионируются, ревьюятся и обновляются.

# Directory structure
specs/
├── features/
│   ├── user-registration.md      # Feature spec
│   ├── order-system.md           # Feature spec
│   └── rate-limiting.md          # Feature spec
├── api/
│   └── openapi.yaml              # API specification
├── architecture/
│   ├── system-overview.md        # Architecture decisions
│   └── data-model.md             # Database design
└── templates/
    ├── feature-spec-template.md  # Template for new features
    └── api-endpoint-template.md  # Template for API endpoints

Traceability: связь спеки с кодом

Каждый PR ссылается на спецификацию, которую он реализует.

# Pull Request Template

## Specification
Link: [specs/features/user-registration.md](specs/features/user-registration.md)

## Tasks Implemented
- [x] Task 1.1: Migration (users table)
- [x] Task 1.2: Migration (confirmation_tokens table)
- [x] Task 2.1: Entity (User)
- [x] Task 2.2: Entity (ConfirmationToken)
- [ ] Task 3.1: Repository (UserRepository) — next PR

## Spec Changes
- Added edge case: re-registration of pending users
  (see commit abc123)

## Verification
- [ ] PHPStan level 9 clean
- [ ] All tests pass
- [ ] Spec requirements covered

Ревью спецификаций в PR

Спецификации ревьюятся отдельно от кода -- и до него.

# Workflow
git checkout -b spec/user-registration

# Write specification
vim specs/features/user-registration.md

# Create spec-only PR
git add specs/
git commit -m "docs(specs): add user registration specification"
git push origin spec/user-registration

# PR review: only spec, no code
# After approval: create implementation branch from spec branch
git checkout -b feat/user-registration
# Implement...
Этап Что ревьюится Кто ревьюит
Spec PR Полнота, однозначность, реализуемость Архитектор / тимлид
Implementation PR Соответствие спеке, качество кода Разработчик / code review
Spec Update PR Изменения спеки по итогам реализации Автор спеки

CI/CD интеграция

Валидация спецификаций в CI

# .github/workflows/spec-validation.yml
name: Spec Validation

on:
  pull_request:
    paths:
      - 'specs/**'
      - 'api/specs/**'

jobs:
  validate-openapi:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Validate OpenAPI spec syntax
      - name: Validate OpenAPI
        uses: char0n/swagger-editor-validate@v1
        with:
          definition-file: specs/api/openapi.yaml

  validate-spec-format:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Check that specs follow template structure
      - name: Check required sections
        run: |
          for spec in specs/features/*.md; do
            echo "Checking $spec..."
            grep -q "## Problem" "$spec" || \
              (echo "Missing: Problem section in $spec" && exit 1)
            grep -q "## Success Criteria" "$spec" || \
              (echo "Missing: Success Criteria in $spec" && exit 1)
            grep -q "## Functional Requirements" "$spec" || \
              (echo "Missing: Functional Requirements in $spec" && exit 1)
          done

  check-spec-links:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Verify that implementation PRs reference specs
      - name: Check spec reference
        if: contains(github.event.pull_request.title, 'feat')
        run: |
          # Check PR body contains link to spec
          echo "${{ github.event.pull_request.body }}" | \
            grep -q "specs/" || \
            (echo "Feature PRs must reference a specification" && exit 1)

Автогенерация документации из OpenAPI

# Generate API docs from OpenAPI spec on merge
generate-api-docs:
  runs-on: ubuntu-latest
  if: github.ref == 'refs/heads/main'
  steps:
    - uses: actions/checkout@v4

    - name: Generate API documentation
      run: |
        npx @redocly/cli build-docs specs/api/openapi.yaml \
          --output docs/api/index.html

    - name: Deploy docs
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: docs/

Маппинг покрытия тестов на требования

<?php

declare(strict_types=1);

namespace Tests\Integration;

use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\CoversClass;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * Spec coverage: specs/features/user-registration.md
 *
 * FR-1.1: ✅ test_register_with_valid_data
 * FR-1.2: ✅ test_register_rejects_invalid_email
 * FR-1.3: ✅ test_register_rejects_duplicate_email
 * FR-1.4: ✅ (verified by checking password_hash format in DB)
 * FR-1.5: ✅ test_new_user_has_pending_status
 * FR-1.6: ✅ test_confirmation_email_dispatched
 */
#[CoversClass(RegistrationController::class)]
final class RegistrationControllerTest extends WebTestCase
{
    #[Test]
    public function register_with_valid_data(): void
    {
        // FR-1.1: System accepts email and password for registration
        $client = static::createClient();
        $client->jsonRequest('POST', '/api/v1/auth/register', [
            'email' => '[email protected]',
            'password' => 'SecurePass1',
            'password_confirmation' => 'SecurePass1',
        ]);

        $this->assertResponseStatusCodeSame(201);
    }

    #[Test]
    public function register_rejects_invalid_email(): void
    {
        // FR-1.2: System validates email format
        $client = static::createClient();
        $client->jsonRequest('POST', '/api/v1/auth/register', [
            'email' => 'not-an-email',
            'password' => 'SecurePass1',
            'password_confirmation' => 'SecurePass1',
        ]);

        $this->assertResponseStatusCodeSame(400);
    }

    // ... remaining tests mapping to FR requirements
}

Практическая структура проекта с SDD

Объединяя все инструменты, вот как выглядит проект, полностью настроенный для SDD:

project/
├── CLAUDE.md                          # Claude Code context
├── AGENTS.md                          # Universal AI context
├── .cursorrules                       # Cursor conventions
├── .github/
│   ├── copilot-instructions.md        # GitHub Copilot context
│   ├── PULL_REQUEST_TEMPLATE.md       # PR template with spec link
│   └── workflows/
│       ├── spec-validation.yml        # CI: validate specs
│       ├── tests.yml                  # CI: run tests
│       └── api-docs.yml              # CI: generate API docs
├── specs/
│   ├── features/
│   │   ├── user-registration.md       # Feature specification
│   │   ├── order-system.md            # Feature specification
│   │   └── rate-limiting.md           # Feature specification
│   ├── api/
│   │   └── openapi.yaml              # API specification
│   ├── architecture/
│   │   ├── system-overview.md         # Architecture decisions
│   │   └── data-model.md             # Database design
│   └── templates/
│       ├── feature-spec.md            # Template: feature spec
│       ├── api-endpoint.md            # Template: API endpoint
│       └── task.md                    # Template: implementation task
├── api/                               # Backend
│   ├── src/
│   ├── tests/
│   └── composer.json
├── app/                               # Frontend
│   ├── components/
│   ├── pages/
│   └── nuxt.config.ts
├── docker-compose.yml
└── Makefile

Шаблон спецификации

# specs/templates/feature-spec.md

# Feature: [Name]

## Problem Statement
[What problem are we solving? Who is affected? What is the impact?]

## Success Criteria
1. [Measurable criterion 1]
2. [Measurable criterion 2]
3. [Measurable criterion 3]

## Functional Requirements

### FR-1: [Requirement Group]
- FR-1.1: [Specific requirement]
- FR-1.2: [Specific requirement]

## Non-Functional Requirements

### NFR-1: Performance
- [Specific performance requirement]

### NFR-2: Security
- [Specific security requirement]

## API Contract
[OpenAPI snippet or reference to specs/api/openapi.yaml]

## Data Models
[Entity definitions with fields, types, constraints]

## Edge Cases
1. [Edge case and expected behavior]
2. [Edge case and expected behavior]

## Testing Strategy
- Unit tests: [what to test]
- Integration tests: [what to test]
- Edge case tests: [what to test]

## Implementation Plan
[High-level steps with dependencies]

## Tasks
[Atomic tasks with verification criteria]

Рекомендации по инструментам

Какой инструмент для какой фазы SDD

Фаза SDD Лучший инструмент Почему
Specify Claude Code / Chat Генерация спеки через диалог
Plan Claude Code Читает спеку, генерирует план
Tasks Claude Code Декомпозирует план на задачи
Implement Claude Code / Cursor Автономная реализация с верификацией
Verify CI/CD + линтеры Автоматическая проверка

Миграция между инструментами

Благодаря AGENTS.md и стандартной структуре specs/ -- переключение между инструментами безболезненно:

Утро: Claude Code (терминал, агентный режим)
  → Реализация задач из спеки автономно

День: Cursor (IDE, визуальный режим)
  → Код-ревью, рефакторинг, отладка

Вечер: Copilot (IDE, автодополнение)
  → Мелкие правки, документация

Спецификации и контексты (.cursorrules, CLAUDE.md, AGENTS.md) -- это портативные артефакты. Они не привязаны к инструменту. Это ваша инвестиция в процесс, а не в продукт.


Итоги

Интеграция SDD с инструментами -- это не про конкретный AI. Это про систему, в которой:

  1. Контекст хранится в файлах проекта (CLAUDE.md, AGENTS.md, .cursorrules)
  2. Спецификации живут в specs/ и версионируются вместе с кодом
  3. CI/CD валидирует спеки и код автоматически
  4. AI-инструменты читают контекст и спеки из файловой системы

Результат: любой разработчик (или AI) может взять проект и понять -- что строится, почему, какие правила, и где спецификации. Это масштабируется. Это воспроизводимо. Это SDD.