Зачем это нужно
Урок 2.10 представлял OpenSpec как lightweight SDD-инструмент, который «особенно хорошо подходит для brownfield». Уроки 15.2-15.10 разобрали установку, концепции, команды и качество спецификаций - но на компактных примерах, где проект умещается в пару экранов кода.
Реальность почти всегда другая: проект существует годы, в нем десятки и сотни тысяч строк, документация частичная или устаревшая, а команда не может остановить разработку на месяц ради «сначала опишем всё». Отсюда главный страх любого внедрения: «Мне придется написать спецификации для всего кода, прежде чем OpenSpec станет полезен?»
Этот урок разбивает официальный ответ документации на этот страх. Коротко: нет, не придется. OpenSpec построен brownfield-first, и его модель внедрения рассчитана именно на большой существующий codebase: спецификации пишутся только под то, что вы собираетесь менять, и накапливаются со временем вокруг реальной работы.
Этот урок открывает блок «Внедрение» (15.11-15.13): сначала адаптация на существующем проекте, затем командная работа и Stores, затем кастомизация под свои конвенции. Материал опирается на цикл изменений из урока 15.2, концепцию дельт из урока 15.3 и паттерны подбора команд из урока 15.8 - если какие-то шаги ниже кажутся незнакомыми, вернитесь к этим трем.
Основная идея
Чтобы начать с OpenSpec, не нужно документировать весь codebase. Спецификации пишутся только под то изменение, которое вы делаете прямо сейчас. Это самое важное, что стоит знать о внедрении OpenSpec в существующий проект.
Спецификации наращиваются по одному изменению за раз. Первое изменение документирует срез системы, которого оно касается; следующее изменение - свой срез; через месяцы openspec/specs/ заполняется естественно, вокруг работы, которую вы и так выполняете. Живая спецификация (living spec) здесь не стартовый проект, а побочный продукт нормальной разработки:
Руководство, которое переводится в этом уроке, формулирует это так: «This guide shows how to start on day one without boiling the ocean» - как начать в первый же день, не пытаясь «переварить океан».
Версия на тридцать секунд
Полное внедрение на существующем проекте умещается в две команды терминала и четыре слэш-команды. В терминале:
$ cd your-existing-project
$ openspec init # создает openspec/ и файлы команд вашего AI-инструмента
Затем в чате coding-агента:
/opsx:explore # необязательно: агент читает область, которую вы затронете
/opsx:propose <настоящее небольшое изменение, которое вам реально нужно>
/opsx:apply
/opsx:archive
Все. После архивации ваши спецификации описывают ровно ту часть системы, которой касалось изменение, - и ничего больше. Это правильный результат. Про остальные 80 000 строк можно больше не думать.
Построчно, что здесь происходит:
cd your-existing-project- вы находитесь в корне существующего репозитория; никакого отдельного «проекта для OpenSpec» создавать не нужно;openspec init- создает каталогopenspec/и файлы команд (skills) для вашего AI-инструмента, как в уроке 15.2;/opsx:explore- необязательный, но полезный шаг: агент читает область, которую вы затронете, до каких-либо предложений;/opsx:propose- берет настоящее небольшое изменение, которое вам реально нужно (не выдуманный пример);/opsx:apply,/opsx:archive- реализация и архивация, после чего дельта изменения вливается вopenspec/specs/.
Обратите внимание: это тот же самый цикл, что и в уроке 15.2. Разница только в точке старта: не чистый лист, а середина большого существующего проекта - и это штатный режим работы OpenSpec, а не компромисс.
Почему delta-first - весь секрет
Изменения в OpenSpec записываются как дельты (delta specs): операции ADDED, MODIFIED, REMOVED. Дельта описывает, что меняется относительно текущего поведения системы, а не систему целиком. Механика дельт подробно разобрана в уроке 15.3; здесь важна именно ее связь с brownfield.
Работа над существующим проектом редко строится с нуля. Вы добавляете поле, чините редирект, ужесточаете таймаут. Дельта позволяет специфицировать одно такое изменение точно - не написав сначала сорокастраничную спецификацию всего, что его окружает. Формат дельты (требования и сценарии остаются на английском - это часть формата):
## ADDED Requirements
### Requirement: API rate limiting
The public API SHALL limit requests per client within a time window.
#### Scenario: Client exceeds the limit
- **WHEN** a client sends more requests than the window allows
- **THEN** the API responds with 429 and does not process the excess requests
Следствие для внедрения: каталог openspec/specs/ не стартует полным и завершенным. Он стартует почти пустым и накапливается. Каждое архивированное изменение вливает в него свою дельту:
Спецификация домена auth/ становится обстоятельной только после того, как вы сделали несколько auth-изменений, - то есть ровно тогда, когда она и должна стать обстоятельной. Не раньше.
Как это выглядит месяц за месяцем
Развернем ту же логику во времени - типичная картина инкрементального внедрения на живом проекте:
Месяц 1: openspec/specs/
api/
spec.md ← единственный домен: первое изменение
(add-api-rate-limiting)
Месяц 2: openspec/specs/
api/
spec.md ← второе api-изменение дополнило spec.md
checkout/
spec.md ← новый домен: add-guest-checkout
Месяц 6: openspec/specs/
api/ ← обстоятельная спецификация:
spec.md выросла из всех api-изменений полугода
checkout/
auth/
search/
Ни на одном из этих этапов не было шага «описать систему целиком». Каждый spec.md появился из архивированных изменений - и описывает только те части, которые команда реально трогала. Остальные 80 000 строк остались за скобками не потому, что про них «забыли», а потому, что спецификация, которую ничто не обновляет, бесполезна.
Здесь же живет ответ на вопрос «когда спецификация домена становится полной?»: никогда заранее. Полной считается та, которая покрывает изменяемое поведение. Как только вы заходите в непокрытую область - /opsx:explore читает код, /opsx:propose пишет дельту, архивация дополняет spec.md.
Инженерный вывод курса: delta-first снимает «проблему холодного старта», на которой спотыкаются тяжеловесные SDD-процессы. «Сначала опишем всё» - это состояние, которое никогда не наступает: работа мешает, описание устаревает раньше завершения. Перенос написания спецификаций в момент реального изменения означает, что спецификация пишется, когда есть и мотивация, и свежее знание кода, - поэтому она не успевает протухнуть.
Первое изменение на реальном codebase
Выберите что-то маленькое и настоящее. Не игрушечный пример, не переписывание компонента. Изменение, которое вы и так собирались сделать на этой неделе. Небольшие первые изменения позволяют изучить workflow с низкими ставками: если что-то пойдет не так, цена урока минимальна.
Весь путь первого изменения на существующем проекте:
Пунктирной разницы между «проектом для обучения» и «рабочим проектом» здесь нет: учебным полигоном становится сама работа, потому что спецификации пишутся только под нее.
Шаг 1. Дайте агенту прочитать затронутую область
Именно здесь /opsx:explore отрабатывает на большом или незнакомом codebase. Направьте агента на часть системы, которую собираетесь менять, и пусть он составит карту, как все устроено, - до каких-либо предложений:
Вы: /opsx:explore
AI: Что хотите исследовать?
Вы: Нужно добавить rate limiting в публичный API, но я не уверен,
как запросы сейчас проходят через middleware.
AI: Прослежу путь... [читает router, стек middleware и конфигурацию]
Запросы попадают в Express, проходят auth-middleware, затем
в контроллеры. Слоя rate limiting сейчас нет. Самая чистая
точка вставки - middleware сразу после auth. Составить скоуп?
Ключевой момент: к моменту proposal агент уже понимает вашу фактическую структуру, поэтому предложение будет подогнано под ваш код, а не под generic-шаблон. По оценке документации, на большом codebase именно эта одна привычка экономит больше всего боли. Отдельно команде /opsx:explore посвящен урок 15.7.
Шаг 2. Предложите изменение
You: /opsx:propose add-api-rate-limiting
Proposal и его дельта-спецификация захватывают только это изменение - rate limiting, а не «весь API раз и навсегда».
Шаг 3. Соберите и заархивируйте
/opsx:apply и /opsx:archive работают так же, как для любого другого изменения. После архивации у вас есть настоящая спецификация поведения rate limiting, рожденная изменением, которое было нужно и так.
Что останется в репозитории после первого изменения
После архивации первого изменения дерево openspec/ выглядит примерно так (структура артефактов подробно разобрана в уроке 15.2):
openspec/
specs/
api/
spec.md # living spec: поведение rate limiting «как есть»
changes/
archive/
add-api-rate-limiting/
proposal.md # зачем делали и что менялось
specs/
api/
spec.md # дельта, влитая в living spec при архивации
tasks.md # чек-лист реализации
Существенно: openspec/specs/api/spec.md описывает только rate limiting. Про аутентификацию, версионирование и остальной публичный API там строк нет - они появятся, только если вы однажды придете менять эти части. А openspec/changes/archive/add-api-rate-limiting/ навсегда сохраняет историю: почему изменение сделали и какой именно дельтой оно вошло в спецификацию.
Инженерный вывод курса: практический критерий выбора первого изменения - три вопроса. Нужно ли оно на этой неделе? Затрагивает ли одну область? Можно ли объяснить его суть в двух предложениях? Если выбранное «изменение» формулируется как «переписать X на Y» - это не первое изменение, а программа на квартал; отложите его и возьмите настоящую маленькую задачу из бэклога.
Экскурс с гидом: /opsx:onboard
Если хочется не делать шаги вручную, а посмотреть весь цикл на собственном коде с комментариями по ходу, есть расширенная команда /opsx:onboard. Она сканирует codebase в поисках небольшого безопасного улучшения, затем проводит вас через предложение, реализацию и архивацию, объясняя каждый шаг.
Сначала включите набор расширенных команд (expanded profile):
$ openspec config profile # выбор расширенных workflow
$ openspec update # применить их к этому проекту
Затем в чате:
/opsx:onboard
Документация называет это самым мягким способом познакомиться с OpenSpec на реальном проекте. После экскурсии у вас остается настоящее (маленькое) изменение, которое можно оставить или отбросить. Справочник команды /opsx:onboard - в уроке 15.5.
Чем /opsx:onboard отличается от /opsx:explore при первом знакомстве:
/opsx:explore |
/opsx:onboard |
|
|---|---|---|
| Кто выбирает, что менять | вы: указываете интересующую область | команда: сканирует codebase и сама находит небольшое безопасное улучшение |
| Что происходит | агент читает код и помогает продумать изменение без обязательств | агент проводит полный цикл: предложение, реализация, архивация - с объяснением каждого шага |
| Результат | понимание области и готовый к /opsx:propose скоуп |
настоящее маленькое изменение, которое можно оставить или отбросить |
| Нужен expanded profile | нет | да: openspec config profile + openspec update |
Если вы уже знаете, какое изменение делать первым, идите путем из предыдущего раздела. Если хочется сначала посмотреть со стороны, как весь цикл проходит по вашему коду, - начните с /opsx:onboard.
«У нас уже есть документация требований»
Типичное возражение команды с историей: «У нас есть PRD / SRS / формальная спецификация / даже TLA+-модели. Что с ними делать?» Ответ документации: хорошо, что есть. Их не импортируют в OpenSpec целиком - и не выбрасывают.
Существующие документы рассматриваются как исходный материал для exploration, а не как спецификации на конвертацию. Начав изменение, вставьте в чат или укажите агенту релевантный раздел документа - и пусть он сформирует из него сфокусированную дельту OpenSpec. Дельта захватывает то поведение, которое меняется сейчас, в тестируемой форме требований и сценариев. Исходные документы остаются там, где лежали, - в качестве фона:
Вы: /opsx:explore
Вы: Вот раздел нашего PRD про checkout. Дальше я реализую
требование «guest checkout».
[вставляет релевантное требование]
AI: [читает его, задает уточняющие вопросы, помогает определить скоуп изменения]
Вы: /opsx:propose add-guest-checkout
Честная причина, почему не работает массовая конвертация: спецификации OpenSpec сознательно behavior-first и скоупированы под изменения. Сорокастраничный PRD - другой артефакт с другой задачей. Одноразовая bulk-конвертация такой документации обычно производит большую неактуальную спецификацию, которой никто не верит. Спецификации, выросшие из реальных изменений, остаются точными - потому что каждое изменение их обновляет.
Инженерный вывод курса: существующая документация требований в этой модели играет ту же роль, что и устное знание кода, - вход для /opsx:explore, а не выход процесса. Ценность PRD не обесценивается: он остается фоном и источником. Но единственный путь информации в openspec/specs/ - через дельту реального изменения.
Организация спецификаций в большом codebase
Спецификации живут в openspec/specs/ и группируются по доменам (domain) - логическим областям, которые соответствуют тому, как ваша команда думает о системе. Возможность (capability) и домен употребляются как синонимы - эта терминология введена в уроке 15.3.
Проектировать всю таксономию доменов заранее не нужно. Папка домена создается тогда, когда первое изменение в этой области в ней нуждается. Типовые способы нарезки:
| Способ нарезки | Примеры доменов |
|---|---|
| По функциональной области | auth/, payments/, search/ |
| По компоненту | api/, frontend/, workers/ |
| По bounded context | ordering/, fulfillment/, inventory/ |
Правило выбора одно: берите то, от чего новичок в проекте кивнет («да, про это payments/»). Уточнить нарезку можно позже - структура каталогов не догма.
Как это выглядит после первых изменений:
openspec/specs/
auth/ # появился после первого auth-изменения
spec.md
api/ # появился, когда дошло дело до rate limiting
spec.md
Два домена - уже работающая структура. Остальные появятся, когда их коснутся реальные изменения.
Инженерный вывод курса: инкрементальное появление доменов - удобный индикатор того, что внедрение идет правильно. Если вы обнаружили себя за проектированием «идеальной таксономии доменов» до первого изменения - остановитесь: это то же самое «boiling the ocean», только перенесенное из спецификаций в структуру каталогов. Правильный порядок обратный: изменение → домен → уточнение нарезки по мере роста.
Монорепозитории и работа между репозиториями
Для монорепозитория простейшая и рекомендуемая модель - один каталог openspec/ в корне репозитория, а домены соответствуют вашим пакетам или сервисам. Этого хватает большинству команд:
monorepo/
openspec/ # один каталог на весь репозиторий
specs/
api/
frontend/
workers/
packages/
services/
Если работа действительно расползается на несколько репозиториев (или несколько пакетов, которые вы считаете отдельными), у OpenSpec есть бета-функция Stores: планирование живет в собственном отдельном репозитории, на который может ссылаться любой из ваших кодовых репозиториев, - план не обязан лежать в openspec/ одного из них. Это beta: команды и формат состояния могут меняться. Ментальная модель и минимальный путь разобраны в уроке 15.12.
Начальный контекст: config.yaml вместо описания всего проекта
Осталось закрыть вопрос, который часто возникает после урока 2.10: где при brownfield-старте живет «начальный контекст проекта» - короткое описание стека и конвенций, которое агент читает перед каждым предложением?
В срезе документации этого модуля эта роль закреплена за секцией context: конфигурационного файла openspec/config.yaml. Рекомендация документации: на большом codebase с устоявшимися конвенциями заполните context: - и каждое предложение начнет уважать ваш стек и паттерны:
# openspec/config.yaml
context:
# короткие, фактические указания о стеке, конвенциях и границах -
# ровно в объеме, который делает предложения уместными
Полная настройка конфигурации проекта - тема урока 15.13. Кастомизация здесь подчиняется той же логике, что и все остальное в этом уроке: не «опишите проект целиком», а «дайте минимум указаний, после которого предложения перестают быть generic».
Инженерный вывод курса: обратите внимание на симметрию. В уроке 2.10 контекст проекта жил в openspec/project.md; в актуальном срезе документации роль начального контекста выполняет секция context: файла openspec/config.yaml (сам project.md в дереве из урока 15.2 уже не фигурирует). Инструмент развивается - сверяйте детали со своей версией CLI, а при чтении старых материалов про OpenSpec проверяйте, о каком срезе идет речь.
Несколько честных предостережений
Документация завершает руководство списком предостережений - все четыре выводятся из модели «от изменения к спецификации».
Сопротивляйтесь желанию дописать спецификации задним числом для всего. Написание спецификаций для кода, который вы не меняете, кажется продуктивным - и обычно не является. Такие спецификации протухают, потому что ничто не заставляет их следовать за реальностью: код меняется без них. Пусть реальные изменения управляют спецификациями.
Держайте первые изменения маленькими. Первые изменения - в такой же мере про освоение ритма, как про поставку. Узкий скоуп делает цикл быстрым, а уроки дешевыми. Типовые размеры первых изменений и как их удерживать - в уроке 15.10.
Коммитьте openspec/ в git. Спецификации и архив принадлежат системе контроля версий рядом с кодом, который они описывают.
Дайте агенту контекст. На большом codebase с сильными конвенциями заполните context: в openspec/config.yaml (раздел выше) - каждое предложение будет учитывать ваш стек и паттерны с первого дня.
Сведем страхи внедрения и ответы на них в таблицу:
| Страх или импульс | Ответ модели brownfield-first |
|---|---|
| «80 000 строк, надо описать все сначала» | Спецификации пишутся только под текущее изменение; остальное накопится |
| «Хочу сразу back-fill спецификациями весь код» | Такие спецификации протухают; пусть изменения управляют specs |
| «У нас есть PRD/SRS - конвертировать?» | Нет: это материал для explore, дельта рождается из реального изменения |
| «Первое изменение - перепишем модуль X» | Первые изменения держите маленькими: ритм важнее размаха |
| «Может, не коммитить openspec/ в git?» | Спецификации и архив живут в version control рядом с кодом |
Инженерный вывод курса: самый частый анти-паттерн внедрения - «сначала приведем документацию в порядок, потом начнем». Он разбивается о тот факт, что «приведение в порядок» без изменений кода не имеет естественного конца и не создает механизма, который удерживал бы написанное актуальным. У модели «от изменения к спецификации» такой механизм есть по построению: каждое изменение обязано пройти через дельту, поэтому актуальность поддерживается самим workflow, а не отдельной дисциплиной.
Карта внедрения: куда идти за деталями
Материал этого урока - карта внедрения; каждый его фрагмент раскрыт в соседних уроках модуля:
| Ситуация при внедрении | Куда идти |
|---|---|
| Полный разбор первого изменения от идеи до архивации | Урок 15.2 |
| Устройство living specs, changes, дельт и архивации | Урок 15.3 |
| Подбор комбинации команд под тип задачи (фича, багфикс, рефакторинг) | Урок 15.8 |
| Как держать изменения маленькими и ревьюить план до кода | Урок 15.10 |
| Командная работа: change ↔ branch ↔ pull request; Stores (beta) | Урок 15.12 |
Конфигурация проекта, секция context:, кастомные схемы |
Урок 15.13 |
Практика
- Возьмите реальный проект - лучше тот, над которым работаете сейчас. Выполните
cdв его корень и запуститеopenspec init. Посмотрите, что появилось. - Выберите первое изменение по трем критериям из этого урока: нужно на этой неделе; затрагивает одну область; объясняется в двух предложениях. Если ничего не приходит в голову - возьмите задачу из бэклога, а не выдумывайте игрушечную.
- Выполните
/opsx:exploreи попросите агента прочитать затрагиваемую область. Проверьте: называет ли он реальные имена файлов и слоев вашего проекта? - Выполните
/opsx:propose <change-name>, проверьте план, затем/opsx:applyи/opsx:archive. - Посмотрите на
git status: что появилось вopenspec/specs/и вopenspec/changes/archive/? Закоммитьте каталогopenspec/. - Оцените результат: сколько строк спецификации описывает ваш проект после первого изменения - и сколько потребовалось бы, чтобы «описать всё» до старта.
- Если не хочется выбирать изменение вручную - включите expanded profile (
openspec config profile, затемopenspec update) и запустите/opsx:onboard: команда сама найдет небольшое безопасное улучшение и проведет цикл с комментариями. Результат можно оставить или отбросить. - Ответьте письменно: какой домен появился в
openspec/specs/и какие еще домены вы ожидаете через месяц - исходя из реального бэклога, а не из структуры кода.
Краткое резюме
Внедрение OpenSpec в существующий проект не начинается с документирования всего codebase - оно начинается с первого реального изменения и идет от изменения к спецификации.
- Пишете спецификации только под то, что меняете;
openspec/specs/стартует почти пустым и накапливается. - Delta-first (
ADDED/MODIFIED/REMOVED) позволяет специфицировать одно изменение точно, без сорокастраничной спецификации вокруг него. - Первое изменение: маленькое, настоящее, из плана на эту неделю;
/opsx:exploreсначала читает затронутую область. /opsx:onboard(expanded profile) проводит весь цикл по вашему коду с комментариями.- Существующие PRD/SRS/TLA+ - исходный материал для exploration, а не то, что конвертируется целиком.
- Домены в
openspec/specs/создаются по мере необходимости; монорепозиторию хватает одного корневогоopenspec/; для межрепозиторной работы - Stores (beta). - Не back-fill-ите всё, держите первые изменения маленькими, коммитьте
openspec/в git, заполнитеcontext:вopenspec/config.yaml.
Вопросы для самопроверки
- Почему OpenSpec не требует описывать весь codebase до начала работы? Как
openspec/specs/наполняется со временем? - Что такое дельта-спецификация и почему формат delta-first особенно точно соответствует brownfield-изменениям?
- По каким критериям стоит выбирать первое изменение на реальном codebase и почему первые изменения рекомендуют держать маленькими?
- Что документация советует делать с уже существующей документацией требований (PRD, SRS, TLA+-моделями) и почему массовая конвертация считается вредной?
- Какие способы нарезки доменов перечисляет документация и каким правилом предлагается выбирать между ними?
- Какая модель организации рекомендуется для монорепозитория? Что предлагается, когда работа выходит за пределы одного репозитория, и каков статус этой функциональности?
Что дальше
Урок 15.12 — «Командная работа и Stores (beta)»: соответствие change ↔ branch ↔ pull request, ревью плана до кода и планирование в отдельном репозитории, когда фича расползается на несколько кодовых баз.