Files
dev-skills/av-dev-code/skills/openspec/SKILL.md
T
avandClaude Opus 5 12882911a9 словарь, манифесты, README: одно слово — одна вещь, одно описание — один дом
- «готовность» значила и «запись можно брать», и «что считается сделанным»;
  второй смысл стал «определением сделанного» — своё же правило про занятое
  слово запрещало это прямо
- «пайплайн» жил в 24 местах вне журналов при том, что DECISIONS фиксирует
  его уход «целиком»; рабочее имя — конвейер
- «чекпоинт» в review значил стадию и проход, в resolve — остановку человеку;
  слово оставлено за остановкой
- у описания плагина было два дома, и три из четырёх уже разошлись. Сведены,
  и класс закрыт машиной: frontmatter.py сверяет plugin.json с marketplace,
  гейт разбужен на *.json
- README врал про односторонние зависимости и терял healthcheck на диаграмме
- перечень агентов в REMAINING отстал на два поколения

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 18:45:39 +03:00

168 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: openspec
description: "Завести и настроить OpenSpec в проекте — openspec init --tools claude, замена закомментированного примера в openspec/config.yaml на настройку канонической формы (язык, правила именования capability, придирки валидатора, адреса паспорта и CLAUDE.md), проверка формы своим скриптом openspec.py (имя файла, схема, незаменённый пример, адреса документов, ключи rules против артефактов схемы) и сверка слепка с живой версией инструмента. Использовать, когда в проекте нет каталога openspec/, когда config.yaml остался примером из коробки, когда заводят новый проект или переводят чужой и дошли до шага OpenSpec, а также когда конвейер отказался работать без источника требований. Каталог openspec нужен именно конвейеру: без него не работают ни opsx:propose, ни ревью дизайна, ни сверка требований."
---
# OpenSpec в проекте
Каталог `openspec/`**предпосылка конвейера**, а не канона документов. Без него
не работают ни `opsx:propose`, ни ревью дизайна, ни `review-specs`: у требований
не остаётся дома. Поэтому заводит и настраивает его этот плагин — тот, кто по
OpenSpec и работает.
Канон документов о файле не высказывается вовсе: `docs.py` его не открывает и об
его отсутствии молчит. Проект без конвейера живёт без OpenSpec законно, и
проверять там нечего. За каноном остаётся одно — **единственный дом**: не
пересказан ли в `context` документ, у которого есть свой файл. Это суждение, а не
форма, и смотрит его агент.
## Два шага, и второй важнее первого
**1. Завести.**
```
openspec init --tools claude
```
Команда кладёт ещё `.claude/skills/openspec-*` и `.claude/commands/opsx/*` — это
её нормальная работа, не трогай их.
**2. Заменить пример.** `openspec init` кладёт `config.yaml`, где `context` и
`rules` — закомментированный пример на английском. **Файл из коробки хуже
отсутствующего:** он есть, он валиден, имя правильное, — и читается как
настроенный, работая как пустой. Узнаётся это по уже написанному предложению: на
другом языке, с capability по имени пакета, без единого `SHALL`.
Пример **заменяется целиком** по образцу:
[references/config-skeleton.md](references/config-skeleton.md).
## Что туда пишут, а что нет
**Это маршрутизатор, а не второй дом фактов.** Внутрь идёт ровно то, что нужно
**в момент порождения артефакта** и чего в этот момент ещё никто не открыл: язык,
правила именования capability, придирки валидатора и **адреса** документов
проекта.
Сюда же — **требования к форме `proposal` и `design`**, на которых стоит чекпоинт
скилла `av-dev-code:resolve`: объяснение человеку собирается из этих двух
артефактов, и требование к ним обязано применяться в момент, когда их пишут, а не
вспоминаться шагом позже. Образец их содержит.
Пересказ паспорта, инвариантов, конвенций и правил ревью сюда **не переносится**.
Место для второго дома здесь самое частое: `context` читается при порождении
каждого артефакта, туда удобно дописать «чтобы агент знал», и так заводятся копии
инвариантов, состава гейта и правил выбора метки. Расходятся они молча, а
замечают это в уже написанном предложении.
Разрез, по которому отличают одно от другого: **утверждение, которое можно
опровергнуть, открыв другой файл проекта, — пересказ; строка, которая говорит,
какой файл открыть, — ссылка.** Машина этот разрез не проверяет; его смотрит
агент `doc-consistency` из плагина канона, когда тот подключён.
Два адреса обязательны — `docs/passport.md` и `CLAUDE.md`: предложение пишется до
того, как кто-либо откроет `docs/`, и без них его пишут, не зная ни границы
домена, ни инвариантов. Отсутствие адреса к **существующему** документу
`openspec.py check` называет отказом; документа нет в проекте — нет и требования.
## Инструмент
```
os="$CLAUDE_PLUGIN_ROOT/skills/openspec/scripts/openspec.py"
python3 $os check --dir <корень> # форма config.yaml в проекте
python3 $os form # слепок формы против живого OpenSpec
```
**Коды выхода — общий словарь скриптов av-dev:** 0 сошлось, 1 дрейф, 2 ошибка
употребления, 3 окружение, 4 внутренний сбой. Ветвись на коде, а не на тексте.
Различать 1 и 3 обязательно: «форма разошлась» — рабочая ситуация, «openspec не
отвечает» — нерабочая.
`check` проверяет форму, и каждая проверка — про молчащий пробел, а не про вкус:
каталог есть; имя именно `config.yaml` (`config.yml` OpenSpec не читает и об этом
не сообщает); ключ `schema` называет ту схему, для которой форма описана;
`context` и `rules.specs` не остались примером, **а `SHALL` назван именно внутри
`rules.specs`** (в `context` он стоит и в образце, поэтому греп по файлу здесь
ничего не значит); `context` называет паспорт и `CLAUDE.md`; ключи под `rules:`
имена артефактов схемы, а не свободные слова. Числа проверок здесь нет намеренно:
оно протухает от каждой добавленной.
**Адреса требуются только к тем документам, которые в проекте есть.** Канон
документов ставится отдельным плагином и может быть не подключён; требовать
ссылку на несуществующий файл значит требовать битую ссылку. Нет
`docs/passport.md` — проверка по нему идёт строкой «не проверялось», и там же
сказано, что без канона конвейер работает вслепую.
### Форма сверяется с живым инструментом
Схема (`spec-driven`) и перечень артефактов (`proposal`, `specs`, `design`,
`tasks`) — **состояние чужого инструмента**, а не наше решение. OpenSpec
переименует артефакт: правила под прежним именем перестанут применяться, конфиг
останется выглядеть написанным, и молчат при этом все три стороны.
Сторож — сравнение версий. `check` каждым прогоном спрашивает `openspec
--version` (десятые доли секунды) и сравнивает `major.minor` с той версией, на
которой форма сверялась; разошлось — **замечание**, не отказ, с именем команды.
Патч-версия в сравнение не берётся намеренно: формы она не меняет, а нагоняй на
каждый багфикс приучает пролистывать весь блок.
Перепроверяет `openspec.py form`: он спрашивает `openspec templates --json`, то
есть перечень артефактов текущей схемы, и печатает, что разошлось с константами.
Дорогой вызов вынесен из `check` сознательно — он стоит втрое дороже опроса
версии, а ответ меняется только вместе с версией. **Чинится расхождение в
плагине, а не в проекте:** константы скрипта, образец
[references/config-skeleton.md](references/config-skeleton.md) и запись в журнал
версий канона.
## Кто зовёт этот скилл
- `av-dev-docs:init` — шагом заведения нового проекта, до первого документа;
- `av-dev-docs:canon` в режиме `adopt` — если на переводимом проекте каталога нет
или `config.yaml` остался примером;
- `av-dev-code:resolve` и `av-dev-code:review` — не вызовом по ходу, а отсылкой:
OpenSpec у обоих жёсткая предпосылка, и на проекте без каталога оба посылают
сюда вместо того, чтобы заводить его руками;
- человек — когда конвейер отказался работать без источника требований.
**Копия.** Дом правила — `shared/plugin-boundary.md` в репозитории плагинов.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из shared/plugin-boundary.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Чужой скилл зовётся полным именем**`av-dev-docs:canon`, `av-dev-tasks:tasks`,
`av-dev-code:review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.pm.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
<!-- /копия: граница-плагинов -->
Здесь это значит: вызов не разрешился — плагина конвейера в проекте нет, и тогда
OpenSpec заводит человек командой выше.
## Чего этот скилл не делает
- **Не пишет спеки и предложения.** Это `opsx:propose` и конвейер задачи.
- **Не ведёт документы канона** — их дом плагин `av-dev-docs`, и адреса в
`context` только на них ссылаются.
- **Не чинит расхождение формы с версией OpenSpec в проекте.** Оно чинится в
плагине: константы скрипта, образец здесь, запись в журнал версий канона.
- **Не судит, ссылается `context` на документы или пересказывает их.** Машине
этот разрез не виден; его смотрит агент `doc-consistency` из плагина канона.
Плагина нет — эту проверку не делает никто, и так и скажи.