Быстрая инициализация базового SDD-пайплайна
Пошагово собираем SDD-петлю specify → clarify → plan → tasks → implement → verify, подключаем OpenSpec, создаём custom schema и проверяем процесс на рабочем демо-проекте.
AI-агент может написать код за несколько минут. Проблема в том, что быстро написать можно не тот код.
Обычный запрос вроде «добавь скидку» оставляет слишком много пространства для догадок:
- какая скидка: процентная или фиксированная;
- можно ли получить отрицательную цену;
- как округлять деньги;
- что делать с невалидными значениями;
- какие тесты считаются достаточными.
Spec-Driven Development, или SDD, меняет порядок работы: сначала команда фиксирует ожидаемое поведение, вопросы, технический план и проверяемые задачи, затем меняет код и сверяет результат со спецификацией.
В этой статье соберём базовую петлю:
specify → clarify → plan → tasks → implement → verifyИменно такой процесс я использую в рабочем frontend-монорепозитории. Затем перенесём его в OpenSpec, создадим отдельную schema и прогоним полный цикл на открытом тестовом проекте CyrilStrone/demo-sdd.
Что получится в конце
После настройки у проекта будет три слоя:
AGENTS.md project constitution
|
v
SDD workflow specify → clarify → plan → tasks → implement → verify
|
v
task artifacts proposal/specs, clarify, plan, tasks, verifyДля каждой задачи появится отдельная папка с историей решений. Агент будет знать:
- Как описать желаемое поведение.
- Когда нужно остановиться и задать вопрос.
- Когда разрешено переходить к реализации.
- Какие команды запустить перед завершением.
- Какие доказательства записать в итоговую проверку.
Готовую структуру, schema, skills, два архива изменений и тестовый код можно сразу посмотреть в репозитории demo-sdd.
Главный принцип: один источник правил
Самая частая ошибка при внедрении SDD - написать одинаковые инструкции в нескольких местах:
AGENTS.md
CLAUDE.md
.cursor/rules/
.github/copilot-instructions.md
custom slash commandsЧерез месяц формулировки расходятся, и разные агенты начинают работать по разным процессам.
Надёжнее разделить ответственность:
В рабочем проекте CLAUDE.md поэтому не повторяет конституцию. Он говорит Claude прочитать AGENTS.md и использовать инструкции из specs/phases/. Codex может читать те же файлы напрямую.
Шесть фаз базовой SDD-петли
1. Specify: что и зачем
Первая фаза отвечает только на вопросы «что меняется?» и «зачем это нужно?». Реализация здесь запрещена.
Минимальный spec.md содержит:
# <TICKET-ID> — <title>
## Goal
<!-- Problem and desired observable outcome. Do not describe implementation. -->
## Context
<!-- Issue link, affected users and system areas. -->
## In scope / out of scope
### In scope
- ...
### Out of scope
- ...
## Acceptance criteria
- [ ] ...
## Assumptions
- ...Критерий приёмки должен быть наблюдаемым. «Создать класс скидок» - способ реализации. «Итоговая цена не становится отрицательной» - проверяемое поведение.
2. Clarify: ворота неопределённости
clarify - ключевая часть процесса. Агент ищет дыры в постановке до того, как они превратятся в код.
Проверяются:
- неоднозначные и противоречивые требования;
- пустые состояния, ошибки, гонки и граничные значения;
- API-контракты и типы;
- безопасность и права;
- совместимость и миграция;
- производительность;
- логирование, метрики и трассировка;
- rollout и rollback.
Шаблон делит вопросы на два класса:
# Clarify
Status: WAITING_FOR_ANSWERS | CLOSED
## BLOCKER questions
1. **What must be decided?**
- Why it matters: ...
- Options: ...
- Recommendation: ...
- Decision owner: architect
- Answer:
## Non-blockers
- **Question** → explicit assumption: ...
## Gap register
| Unknown | Impact | Assumption / status | Owner |
| --- | --- | --- | --- |
| ... | ... | ... | ... |Правило ворот простое:
Пока хотя бы один BLOCKER не получил явный ответ,
planне начинается.
Non-blocker не обязан останавливать работу, но принятое допущение должно остаться в clarify.md. Так скрытая догадка превращается в видимое решение, которое можно проверить на ревью.
3. Plan: как будем менять систему
Только после закрытия clarify можно проектировать реализацию.
Хороший plan.md называет:
- подход;
- реальные файлы и модули;
- решения и рассмотренные альтернативы;
- риски и способы их снизить;
- совместимость;
- миграцию и откат;
- точные проверки.
# Plan
## Approach
## Affected files and modules
## Decisions and alternatives
## Compatibility, risks, and rollback
## Open assumptions
## VerificationПлан должен быть минимальным и аддитивным. Если во время планирования появилась новая продуктовая или архитектурная развилка, её нужно вернуть в clarify, а не закрыть молча.
4. Tasks: исполнимый чек-лист
tasks.md превращает план в небольшие шаги. Каждый шаг содержит собственный способ проверки:
# Tasks
## 1. Implementation
- [ ] 1.1 Add the function; verify `node --check src/discount.js` exits with code 0.
- [ ] 1.2 Add the normal-case test; verify `199.99 - 20` returns `179.99`.
## 2. Verification
- [ ] 2.1 Run `npm run check` and verify all tests pass.Если задача звучит как «разобраться в коде» или «протестировать всё», значит discovery не был завершён на предыдущих фазах.
5. Implement: исполнение плана
На этой фазе агент:
- Перечитывает спецификацию,
clarify.md, план и задачи. - Выполняет задачи по порядку.
- Отмечает checkbox только после проверки результата.
- Не расширяет scope без возврата в
clarifyилиplan.
Если в процессе обнаружился вопрос, от которого меняется поведение, это не приглашение угадать ответ. Петля делает шаг назад.
6. Verify: доказательная сверка
verify.md - не пересказ выполненной работы. Это сопоставление каждого критерия с доказательством:
# Specification verification
## Acceptance criteria
- [x] Final price never falls below zero
— evidence: boundary test passes for equal and larger discounts.
## OpenSpec scenarios
- [x] Fixed discount / Discount exceeds price
— evidence: automated test returns `0`.
## Checks
- `npm run check`: 6 passed, 0 failed.
## Specification deviations
- None.
## Residual gaps
- Currency-aware arithmetic remains out of scope.Если критерий не закрыт, задача возвращается в implement или plan. Формулировка «почти готово» не заменяет доказательство.
Быстрый vendor-neutral setup
OpenSpec полезен, но базовая петля не должна зависеть от одного AI-инструмента. Сначала её можно развернуть обычными Markdown-файлами:
project/
├── AGENTS.md
└── specs/
├── README.md
├── phases/
│ ├── specify.md
│ ├── clarify.md
│ ├── plan.md
│ ├── tasks.md
│ ├── implement.md
│ └── verify.md
└── _template/
├── spec.md
├── clarify.md
├── plan.md
├── tasks.md
└── verify.mdВ AGENTS.md добавьте короткий обязательный контракт:
## SDD loop
Work strictly in this order:
`specify → clarify → plan → tasks → implement → verify`.
Task artifacts live in `specs/<TICKET-ID>/`.
An open BLOCKER in `clarify.md` stops planning and implementation.
Do not guess material product or architecture decisions.
Run the project checks defined below before completing verify.
## Commands
- Fast check: `<project command>`
- Tests: `<project command>`
Git remains under human control. Do not commit or push unless explicitly requested.В specs/README.md оставьте таблицу фаз и правила переходов. Подробности пишите только в specs/phases/<phase>.md.
Для новой задачи копируйте шаблоны:
specs/DEMO-123/
├── spec.md
├── clarify.md
├── plan.md
├── tasks.md
└── verify.mdТакой каркас уже работает в Codex, Claude Code и других агентах, способных читать инструкции из репозитория. Интеграции конкретного инструмента должны лишь направлять агента в нужный phase-файл.
Дополнительные рельсы
Markdown-процесс полезно поддержать автоматикой, но вводить её лучше постепенно.
Мягкое напоминание перед push
Git hook может проверить, существует ли папка спеки для задачной ветки:
TASK_RE='^((feat|fix|docs)/)?[A-Za-z][A-Za-z0-9_]*-[0-9]+([_/].*)?$'
if printf '%s' "$branch" | grep -qE "$TASK_RE"; then
ticket=$(printf '%s' "$branch" | grep -oE '[A-Za-z][A-Za-z0-9_]*-[0-9]+' | head -n1)
if [ -n "$ticket" ] && [ ! -d "specs/$ticket" ]; then
echo "No specs/$ticket/ found. Create it if this task uses SDD."
fi
fiНа feature-ветках удобно оставить проверку предупреждением. На release-ветках CI уже может блокировать сборку, если обязательная спецификация отсутствует или clarify не закрыт.
Merge request checklist
В шаблон MR достаточно добавить пять пунктов:
## SDD checklist
- [ ] Specification exists.
- [ ] Clarify gate is closed; no BLOCKER remains.
- [ ] Plan and tasks match the implementation.
- [ ] Verification contains evidence for every acceptance criterion.
- [ ] Project checks pass.CODEOWNERS можно настроить на AGENTS.md, phase-инструкции и шаблоны. Тогда изменение самого процесса потребует ревью владельца архитектуры или платформенной команды.
Зачем здесь OpenSpec
OpenSpec превращает набор Markdown-договорённостей в управляемый workflow для AI-агентов.
Он полезен сразу в нескольких местах:
- инициализирует структуру проекта и интеграции агентов;
- хранит постоянные capability specs отдельно от изменений;
- строит граф зависимостей артефактов;
- показывает статус change;
- строго валидирует требования и сценарии;
- после завершения переносит delta specs в основной контракт системы;
- архивирует историю изменения вместе с планом и решениями.
Важно различать два типа команд. openspec ... запускается в терминале, а команды или skills агента вызываются в его чате. Это отдельно подчёркнуто в официальной инструкции How Commands Work.
Установка OpenSpec
Для актуальной версии OpenSpec нужен Node.js 20.19.0 или новее. Требование и варианты установки перечислены в официальной инструкции.
Проверяем Node.js:
node --versionГлобальная установка из документации:
npm install -g @fission-ai/openspec@latest
openspec --versionВ demo-sdd я закрепил версию 1.13.0 как dev dependency, чтобы повторный запуск использовал тот же CLI:
npm install --save-dev @fission-ai/openspec@1.13.0
npx openspec --versionДля команд ниже глобальная и локальная установка эквивалентны. При локальной добавляйте npx.
Инициализация проекта для Codex
Из корня проекта запускаем:
npx openspec init \
--tools codex \
--language en \
--force \
--no-animationКоманда создаёт:
.agents/skills/openspec-*/
openspec/
├── config.yaml
├── specs/
└── changes/Codex использует skills, поэтому OpenSpec не создаёт для него /opsx:* slash commands. Основной быстрый сценарий вызывается в чате так:
$openspec-propose "add fixed discount calculation"
$openspec-apply-change
$openspec-archive-changeУ других агентов синтаксис отличается. Актуальные варианты перечислены в OpenSpec troubleshooting.
Как Codex понимает, что нужно использовать SDD-петлю
Здесь нет скрытого переключателя «SDD mode». Codex получает нужное поведение из трёх независимых слоёв: постоянных инструкций проекта, agent skills и исполняемых проверок.
1. AGENTS.md задаёт обязательные правила проекта
Codex читает AGENTS.md перед началом работы и собирает цепочку инструкций от корня репозитория до текущей директории. Это штатный механизм настройки проекта, описанный в официальной документации Codex.
Поэтому в AGENTS.md демо-проекта записана не подсказка для отдельного запроса, а конституция всего репозитория:
- изменение поведения сначала проходит через SDD;
- фазы выполняются в заданном порядке;
- материальные требования нельзя додумывать;
- новый баг возвращает активный change к самому раннему затронутому артефакту;
- архивированный change не переписывается — для него создаётся follow-up;
- завершение требует актуального
verify.mdи успешногоnpm run check:all.
Даже запрос «исправь баг» таким образом уже приходит к Codex вместе с контекстом о петле. Но AGENTS.md задаёт политику — он не является отдельной командой и сам по себе не запускает OpenSpec CLI.
2. Skills объясняют, как выполнить конкретную операцию
После openspec init --tools codex в .agents/skills появляются шесть базовых repo-local skills OpenSpec. В демо к ним добавлены три тонких skill для нашей полной петли:
Codex сначала видит name и description каждого skill. Затем skill активируется одним из двух способов:
- Явно — пользователь пишет
$openspec-proposeили другой skill в запросе. - Неявно — Codex выбирает skill, потому что задача соответствует его
description.
Оба способа поддерживаются Codex и описаны в официальной документации по skills. Для воспроизводимого SDD-процесса лучше вызывать ключевые переходы явно:
$openspec-propose Use the sdd-loop schema to add fixed discount calculation.
$openspec-apply-change Implement the active change.
$openspec-archive-change Archive the change after current verification passes.Уточнение Use the sdd-loop schema здесь намеренное: стандартный skill OpenSpec универсален и не обязан заранее знать имя нашей custom schema.
3. Schema и guard превращают договорённость в проверяемую петлю
Skill — это инструкция для агента, а не state machine. Фактический граф артефактов хранится в openspec/schemas/sdd-loop/schema.yaml. Именно schema сообщает OpenSpec, что plan зависит от артефакта clarify, tasks — от specs и plan, а apply начинается после готовых задач. Требование закрыть clarify обеспечивают AGENTS.md и машинный guard.
Остаются состояния, которые OpenSpec 1.13.0 не определяет только по графу: действительно ли код уже реализован, не устарел ли verify.md и совпадают ли его fingerprints с текущими файлами. Их проверяет scripts/sdd-state.mjs.
Итоговая модель выглядит так:
user request
↓
AGENTS.md: SDD обязателен и определяет правила возврата
↓
OpenSpec skill: выполняет propose / update / apply / archive
↓
sdd-loop schema: строит граф артефактов
↓
sdd-state guard: не пропускает stale или недоказанный результатЭто важное разделение ответственности. Если полагаться только на неявный выбор skill, агент обычно распознает подходящий workflow, но ключевой переход остаётся модельным решением. Явный $openspec-*, обязательный AGENTS.md и машинный guard вместе делают процесс предсказуемым.
Custom-фазы clarify и verify в этом примере являются артефактами schema, а не отдельными сгенерированными skills. Инструкцию для verify поэтому можно получить напрямую:
npx openspec instructions verify --change <change-name> --jsonВ demo-sdd эти три обёртки уже реализованы:
$sdd-start Add a new capability.
$sdd-rework Reopen <change-name> after the observed regression.
$sdd-verify Verify <change-name>.Они намеренно остаются тонкими и не дублируют весь OpenSpec workflow. $sdd-start гарантирует --schema sdd-loop и останавливается перед кодом. $sdd-rework выбирает правильную точку возврата, сохраняет историю цикла и останавливается перед повторным apply. $sdd-verify запускает проверки, получает fingerprints, формирует evidence-based verify.md и выполняет npm run check:all, но не архивирует change. Общие правила по-прежнему живут в AGENTS.md, schema и guard.
Как совместить базовую петлю с OpenSpec
Стандартная schema OpenSpec использует артефакты:
proposal → specs + design → tasks → apply → archiveНаша петля требует явных clarify и verify. Соответствие будет таким:
OpenSpec разделяет общее описание изменения и поведенческий контракт. Поэтому одна логическая фаза specify создаёт два вида артефактов:
proposal.mdфиксирует цель, scope и capabilities;specs/<capability>/spec.mdфиксирует требования и сценарии.
Это полезное разделение: proposal со временем уходит в архив, а capability spec после archive становится частью постоянного описания системы.
Создание custom schema
В OpenSpec 1.13.0 команды schema помечены как experimental. Команда schema init умеет быстро собрать schema из стандартных proposal, specs, design и tasks, но произвольные артефакты вроде clarify через её флаг --artifacts пока не принимаются.
Поэтому рабочий путь начинается с fork:
npx openspec schema fork spec-driven sdd-loop --forceПосле этого редактируем:
openspec/schemas/sdd-loop/
├── schema.yaml
└── templates/
├── proposal.md
├── spec.md
├── clarify.md
├── plan.md
├── tasks.md
└── verify.mdГлавная часть schema.yaml - граф артефактов:
name: sdd-loop
version: 1
description: Basic SDD loop
artifacts:
- id: proposal
generates: proposal.md
template: proposal.md
instruction: Describe WHAT changes and WHY, not implementation.
requires: []
- id: specs
generates: "specs/**/*.md"
template: spec.md
instruction: Create testable OpenSpec delta requirements and scenarios.
requires: [proposal]
- id: clarify
generates: clarify.md
template: clarify.md
instruction: Stop while any material BLOCKER has no explicit answer.
requires: [proposal, specs]
- id: plan
generates: plan.md
template: plan.md
instruction: Design the smallest solution after the clarify gate is closed.
requires: [clarify]
- id: tasks
generates: tasks.md
template: tasks.md
instruction: Create ordered checkbox tasks with verification.
requires: [specs, plan]
- id: verify
generates: verify.md
template: verify.md
instruction: Record evidence after implementation and completed tasks.
requires: [tasks]
apply:
requires: [tasks]
tracks: tasks.md
instruction: Implement tasks in order and return to clarify on new blockers.В openspec/config.yaml фиксируем schema и добавляем проектный контекст:
schema: sdd-loop
context: |
Language: English.
All project files and OpenSpec artifacts must be written in English.
Before implementation, read AGENTS.md as the project constitution.
Do not guess material decisions: record them in clarify.md.
rules:
clarify:
- Never close the gate while a BLOCKER has no explicit answer
verify:
- Every completed criterion must reference concrete evidence
operations:
apply:
guidance:
- Run npm run check before declaring implementation completeВ проверенной версии 1.13.0 команда new change надёжнее работает с явным
--schema sdd-loop, даже когда schema уже записана в config.yaml. Поэтому в CLI-командах
ниже я не полагаюсь на неявное разрешение schema. В запросе к agent skill её тоже лучше назвать.
Проверяем schema:
npx openspec schema validate sdd-loop --verboseОжидаемый результат:
Validating sdd-loop...
Checking schema.yaml exists...
Parsing YAML...
Validating schema structure...
Checking template files...
Dependency graph validation passed
✓ Schema 'sdd-loop' is validВажное ограничение verify
Граф OpenSpec описывает зависимости файлов, но не отдельное состояние «код уже реализован». Поэтому после появления tasks.md артефакт verify технически становится ready, хотя создавать его нужно только после apply.
Есть и второй нюанс: OpenSpec считает custom artifact готовым по наличию файла. Он не читает Status: CLOSED внутри clarify.md и автоматически не инвалидирует старый verify.md после изменения плана или кода.
Поэтому одних текстовых инструкций недостаточно. В demo-sdd ограничение снимается на трёх уровнях:
- В instruction для
verifyявно написать: создавать только после реализации и закрытия всех checkbox вtasks.md. - В
AGENTS.mdзапретить объявлять задачу готовой без реальных проверок и доказательств. - Добавить машинный
scripts/sdd-state.mjs, который проверяет состояние петли и свежесть verification fingerprints.
При этом apply уже доступен, как только завершены tasks. Агенту не требуется заранее создавать verify.md.
Что делать, если задача вернулась с багом
Возврат зависит от того, успели ли мы архивировать change.
bug found
|
+-- change is active
| |
| +-- spec is correct, code is wrong
| | → tasks → implement → verify
| |
| +-- spec misses the case
| | → specs → clarify → plan → tasks → implement → verify
| |
| +-- intent changed materially
| → create a separate change
|
+-- change is archived
→ create a follow-up bugfix change
→ MODIFIED requirement + regression scenario
→ clarify → plan → tasks → implement → verify → archiveПока change активен, его артефакты являются живым планом: их можно уточнить и повторно пройти downstream-фазы. OpenSpec описывает именно такую модель в Editing & Iterating on a Change.
Архив переписывать нельзя. После archive delta specs уже объединены с постоянной спецификацией, а папка change хранит аудит принятых решений. Новый баг оформляется отдельным change, который ссылается на предыдущий архив и модифицирует существующую capability.
В AGENTS.md для этого добавлен обязательный rework protocol:
## Rework protocol
1. Stop and classify the finding:
implementation mismatch, incomplete specification, or changed intent.
2. Update the earliest affected artifact.
3. Add a rework-history entry and a regression scenario.
4. Mark existing verification STALE and reopen affected tasks.
5. Repeat implement and verify.
6. Never edit an archived change; create a follow-up change.clarify.md теперь сохраняет историю повторных циклов:
## Rework history
| Cycle | Trigger | Classification | Return to | Invalidated artifacts | Regression scenario |
| --- | --- | --- | --- | --- | --- |
| 2 | Incorrect rounding | Incomplete specification | specs | plan, tasks, verify | Half-cent price |Так видно не только итоговое решение, но и почему работа вернулась назад.
Как определяется устаревший verify
В verify.md появились машинно-проверяемые поля:
Status: CURRENT
Cycle: 2
Planning fingerprint: `sha256:...`
Implementation fingerprint: `sha256:...`Planning fingerprint включает proposal.md, clarify.md, plan.md, tasks.md и все delta specs. Состояния checkbox нормализуются, поэтому само закрытие задачи не меняет fingerprint, а изменение её смысла меняет.
Implementation fingerprint строится по путям из sdd.config.json:
{
"schema": "sdd-loop",
"implementationPaths": ["package.json", "src", "test"]
}Перед созданием verify.md fingerprints печатаются командой:
npm run sdd:fingerprint -- <change-name>Проверка состояния запускается отдельно или внутри общего check:
npm run check:sdd-state
npm run check:allGuard блокирует завершение, если:
- существует
plan.md, ноclarify.mdне имеетStatus: CLOSED; - BLOCKER не получил явный ответ;
- rework cycle не ссылается на regression scenario;
verify.mdпоявился при открытых tasks;- все tasks закрыты, но
verify.mdотсутствует; - verification имеет статус
STALE; - planning или implementation fingerprint больше не совпадает.
Тестовый change
В demo-sdd я создал change для фиксированной скидки:
npx openspec new change add-fixed-discount \
--schema sdd-loop \
--description "Add a fixed discount with a zero lower bound"Начальный статус показал корректный граф:
proposal ready
specs blocked by proposal
clarify blocked by proposal, specs
plan blocked by clarify
tasks blocked by specs, plan
verify blocked by tasksДля каждого артефакта OpenSpec отдаёт итоговый путь, шаблон, зависимости и инструкции:
npx openspec instructions proposal \
--change add-fixed-discount \
--jsonПосле заполнения planning artifacts implementation-контекст можно проверить командой:
npx openspec instructions apply \
--change add-fixed-discount \
--jsonOpenSpec распознал все шесть задач из tasks.md и сообщил состояние ready.
Что было реализовано в demo-sdd
Исходный модуль в demo-sdd умел считать процентную скидку. Первый change добавил отдельную функцию, а follow-up с багом округления перевёл вычисление в integer cents. Текущая реализация выглядит так:
function toCents(value) {
const binaryRoundingCorrection = Number.EPSILON * Math.max(1, value);
return Math.round((value + binaryRoundingCorrection) * 100);
}
export function calculateFixedDiscount(price, amount) {
if (!Number.isFinite(price) || price < 0) {
throw new RangeError('price must be a non-negative finite number');
}
if (!Number.isFinite(amount) || amount < 0) {
throw new RangeError('amount must be a non-negative finite number');
}
const priceInCents = toCents(price);
const amountInCents = toCents(amount);
return Math.max(0, priceInCents - amountInCents) / 100;
}Тесты покрыли:
- обычное вычитание;
- округление до двух знаков;
- скидку, равную цене;
- скидку больше цены;
- отрицательные значения;
NaNиInfinity.
Проверка кода:
npm run checkФактический результат:
tests 7
pass 7
fail 0Строгая проверка change:
npx openspec validate --all --strict --no-interactiveРезультат до архивирования:
✓ change/add-fixed-discount
Totals: 1 passed, 0 failedOpenSpec также показал завершение всех артефактов:
Change: add-fixed-discount
Schema: sdd-loop
Progress: 6/6 artifacts complete
[x] proposal
[x] specs
[x] clarify
[x] plan
[x] tasks
[x] verifyАрхивирование и постоянная спецификация
После реализации и verify change архивируется:
npx openspec archive add-fixed-discount -y --jsonOpenSpec выполнил две операции:
- Перенёс полную историю в
openspec/changes/archive/2026-09-12-add-fixed-discount/. - Обновил постоянный контракт в
openspec/specs/fixed-discount/spec.md.
Фактический отчёт:
archivedAs: 2026-09-12-add-fixed-discount
specsUpdated: true
added requirements: 2После archive были запущены четыре проверки:
npm run check
npx openspec schema validate sdd-loop --verbose
npx openspec validate --all --strict --no-interactive
npx openspec validate --archived --strict --no-interactiveВсе завершились успешно:
code tests: 7 passed, 0 failed
schema: valid
main spec: 1 passed, 0 failed
archived change: 1 passed, 0 failedТак проверяется не только Markdown-структура, но весь жизненный цикл: change → implementation → evidence → permanent spec → archive.
Проверка повторного цикла на реальном баге
После архивирования первого change обнаружился настоящий пограничный случай:
calculateFixedDiscount(1.005, 0) => 1Для денежного half-up ожидалось 1.01. Предыдущая спецификация говорила только «round to two decimal places», поэтому одновременно обнаружились баг реализации и неполный контракт округления.
Поскольку исходный change уже находился в archive, я создал follow-up:
npx openspec new change fix-fixed-discount-rounding \
--schema sdd-loop \
--description "Define deterministic half-up rounding for fixed discounts"Новый delta spec использовал MODIFIED Requirements, полностью повторил изменяемое требование и добавил regression scenario:
#### Scenario: Price is exactly half a cent above one unit
- **WHEN** the original price is `1.005` and the fixed discount is `0`
- **THEN** the system returns `1.01`Реализация теперь округляет price и discount в integer cents до вычитания. Отдельная проверка calculateFixedDiscount(1.004, 0.005) === 0.99 доказывает именно порядок «round inputs → subtract cents», а не случайное совпадение результата.
Во время проверки guard действительно поймал устаревание: после уточнения текста задач старый planning fingerprint больше не совпал и check:sdd-state завершился с ошибкой. После повторной сверки fingerprint был обновлён, а полный pipeline прошёл.
Follow-up change был архивирован как:
openspec/changes/archive/2026-09-12-fix-fixed-discount-rounding/OpenSpec сообщил:
specsUpdated: true
modified requirements: 1После двух циклов итоговые проверки дали:
code and guard tests: 7 passed, 0 failed
schema: valid
permanent spec: 1 passed, 0 failed
archived changes: 2 passed, 0 failed
active changes: noneКак работать каждый день
Для новой задачи достаточно такого сценария.
Если постановка ещё сырая
В чате агента:
$openspec-exploreExplore не создаёт артефакты и помогает сначала разобраться в проблеме. OpenSpec называет это полезной привычкой для задач с неясным scope в Getting Started.
Если задача уже понятна
В чате Codex:
$sdd-start Add fixed discount calculation.Этот project-specific skill сам укажет --schema sdd-loop и построит planning artifacts. Низкоуровневый эквивалент через сгенерированный OpenSpec skill выглядит так: $openspec-propose Use the sdd-loop schema to add fixed discount calculation. При настоящем BLOCKER оба пути должны остановиться на clarify и запросить решение.
После ревью артефактов отдельным запросом:
$openspec-apply-changeЕсли во время или после реализации найден новый баг, сначала верните change в петлю:
$sdd-rework Reopen <change-name> after <observed failure>.Skill классифицирует находку, обновит самый ранний затронутый артефакт, добавит regression scenario, пометит старую verification как STALE и подготовит задачи для повторного $openspec-apply-change.
После завершения реализации запустите отдельную доказательную проверку:
$sdd-verify Verify <change-name>.Она получает инструкцию custom artifact, запускает проверки, записывает fingerprints и только после этого выполняет полный npm run check:all. Эквивалентную низкоуровневую инструкцию можно получить вручную:
npx openspec instructions verify --change <change-name> --jsonКогда $sdd-verify завершился зелёным результатом, change можно отдельно архивировать через $openspec-archive-change <change-name>.
Что стоит вынести в CI
Минимальный CI guard:
npm run check:sdd-state
npx openspec schema validate sdd-loop
npx openspec validate --all --strict --no-interactive
npx openspec validate --archived --strict --no-interactiveДобавьте рядом обычные проверки проекта:
npm run checkДля feature-веток можно сначала сделать guard предупреждением. Когда команда привыкнет к процессу, включить блокировку для release-веток или protected branches.
Когда SDD помогает, а когда мешает
Полная петля оправдана, если задача:
- меняет наблюдаемое поведение;
- затрагивает несколько модулей или команд;
- содержит продуктовые или архитектурные развилки;
- требует миграции или обратной совместимости;
- имеет дорогую ошибку реализации;
- выполняется AI-агентом с широким доступом к проекту.
Для исправления опечатки или механического rename шесть артефактов будут лишними. В OpenSpec для изменений без spec-level поведения существует skip_specs: true; не нужно выдумывать capability только ради успешной валидации.
Главная цель SDD - не увеличить количество Markdown-файлов. Цель - сделать решения видимыми до кода и проверяемыми после него.
Практические правила
- Храните спецификации рядом с кодом и ревьюйте их как код.
- Не дублируйте phase-инструкции для каждого агента.
- Сделайте
clarifyнастоящими воротами, а не формальностью. - Пишите критерии в терминах поведения, а не классов и файлов.
- Каждая задача должна называть собственную проверку.
- Не отмечайте checkbox до выполнения проверки.
- В
verify.mdзаписывайте доказательства, а не уверенность агента. - Сохраняйте расхождения и GAP явно.
- Начните с warn-only CI, затем усиливайте правила.
- Закрепляйте версию OpenSpec в проекте, если важна воспроизводимость schema.
- После archive не переписывайте историю: оформляйте баг отдельным change с
MODIFIED Requirement. - Инвалидируйте verify автоматически, если изменился planning или implementation fingerprint.
Итог
Базовый SDD-пайплайн можно развернуть без тяжёлой платформы: достаточно AGENTS.md, шести phase-инструкций и пяти шаблонов. Уже это создаёт общий путь для людей, Codex, Claude Code и других AI-агентов.
OpenSpec добавляет поверх этого полезную механику: dependency graph, agent skills, строгую проверку требований, постоянные capability specs и архив изменений. Custom schema позволяет сохранить собственную петлю specify → clarify → plan → tasks → implement → verify, не отказываясь от OpenSpec-формата.
Проверка на demo-sdd закрыла два последовательных цикла: исходную capability и найденный после archive баг округления. Schema валидна, задачи распознаются, apply получает правильный контекст, семь тестов проходят, stale verify блокируется, strict validation зелёная, оба архива проверяются, а постоянная спецификация содержит новый regression scenario.
То есть минимальный SDD здесь не теоретический шаблон. Это воспроизводимый процесс, который можно положить в новый репозиторий и использовать с первой реальной задачи.