Files
dev-skills/README.md
T
avandClaude Opus 5 52cc4d05d4 разбор находок doc-consistency: остатки модели типов и копии в ссылки
Первый прогон агента — по репозиторию, который его же и содержит. Два
прохода, 17 находок, все подтверждены по файлам.

Пять находок — остатки прежней модели типов в файлах, до которых я не
дошёл двумя коммитами раньше. adopt.md держал имена секций роадмапа
канона 2 («порядка», «темы») и «пустой goal законен только у идеи»;
from-review.md и TODO.md — упразднённый [idea]; task-batch в другом
плагине — «задачи-идеи». Правку модели я вёл от документов, которые
менял, а не от тех, что на них ссылаются: grep по упразднённому слову
дал бы все пять за минуту.

Самая дорогая находка оказалась моей и свежей. Таблица типов в canon.md
объявляла цель у fix запрещённой, а tasks/SKILL.md и task-fix.md —
необязательной; код на стороне вторых. Копия разошлась с домом за один
день, обе половины писал один проход. Поправлено не значение, а причина:
canon.md дважды объявлял, что фиксирует только словарь типов, — значит
колонкам «разделы» и «цель» в нём не место. Осталась таблица из двух
колонок и ссылка на дом схемы.

Перечень «чем держат проект» пересказывался втроём и разъехался:
«метрики и логи» против «мониторинга», «проверки» есть в двух из трёх.
При этом tasks/SKILL.md ссылался на дом рядом с собственным пересказом —
ссылка не мешает копии разойтись, если копия всё равно стоит. Перечень
остался в canon.md, два места ссылаются.

README пересказывал раскладку канона блоком кода, и копия была уже
неполна — не хватало путей, чьё отсутствие docs.py считает нарушением.
Заменено ссылкой. Там же измеренное число из DECISIONS III заменено
ссылкой на решение.

REMAINING дублировал два отмеченных сделанными пункта TODO и держал
счётчики, которые обязан двигать человек: «двенадцати тем и 16 коммитов»
(стало 28 и 52), «три неизмеренных изменения» (стало больше). Счётчики
отменены как класс, причина записана в шапку. Открытый вопрос про парный
статус ADR переформулирован: судья появился, открыт остался охват.

Три противоречия вне av-dev-pm: --roadmap-sections перечислен среди
флагов init прозой того же файла, объявляющей, что его нет; review-ops
берёт журнал docs/review.md и тут же объявляет историю инцидентов
принципиально недоступной; «честный предел» конвейера отменял целиком
документ docs/research/. Плюс битый якорь ссылки на раздел вычитки.

Находка про Co-Authored-By снята как неверная: агент прочитал
av-dev-git/skills/commit/SKILL.md как описание практики этого
репозитория, а это продукт, уезжающий в чужие проекты. Устав агента не
различает «документ про нас» и «документ про то, что мы производим» —
остаток записан в REMAINING, в устав пока не дописан.

DECISIONS тема 29 (ЧЧШШ–ЮЮЯЯ, следствия 109–113).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 11:21:40 +03:00

328 lines
20 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.
# av-dev-skills
Личный маркетплейс плагинов для разработки. Процесс имени не имеет — он и есть
`av-dev`.
Что решено и почему — [DECISIONS.md](DECISIONS.md). Что осталось сделать —
[TODO.md](TODO.md) и [REMAINING.md](REMAINING.md). Как процесс дошёл до текущей
формы — [HISTORY.md](HISTORY.md).
## Плагины
- **av-dev-pm** — управление продуктом. Владеет всем `docs/`.
- `init` — новый проект: интервью по свободному описанию замысла → первичная
документация;
- `canon` — привести проект к канону документов: `check` / `adopt` /
`upgrade`, плюс скрипт `docs.py`. Там же живёт язык проектных текстов —
информационный стиль, англицизмы, жаргон. Смысловую часть, которой скрипт
не видит, судят два агента: `doc-consistency` (документы между собой и с
openspec) и `doc-code-drift` (документы против кода);
- `docs` — содержимое канона по ходу разработки: ADR из архивного
`design.md`, промоут конвенций, запись в разведку и журнал ревью, чистка
архитектуры;
- `tasks` — задачи и цели каталогом markdown-файлов, у каждой записи тип
(`goal`, `feature`, `fix`, `chore`, `research`), и тип задаёт её схему;
вычитывают их два отдельных прохода: `task-form` (форма записи) и
`doc-wording` (язык);
- `session` — ритуал между спринтами и ведение спринта.
- **av-dev-pipeline** — исполнение. **Требует OpenSpec.**
- `task-pipeline` — задача через полный цикл SDD, от постановки до коммита;
- `task-batch` — несколько задач разом, каждая в своём worktree;
- `review-pipeline` — конвейер ревью: гейт, сверка со спеками, враждебные
постановки, эксплуатационный постмортем, независимая реализация,
архитектура, обязательный триаж. Девять агентов-проходов, четыре ступени
стоимости: `quick`, `standard`, `wide`, `deep`.
- **av-dev-git** — `commit`: сообщения в личном стиле.
- **av-dev-backlog** — **устарел**, заменён `av-dev-pm`. Живёт до перевода
последнего проекта; как снять с проекта — [Снятие](#снятие).
Соглашение об именах: имя **плагина** длинное с префиксом `av-dev-`, имена
**скилов** внутри — короткие. Вызов выходит вида `/av-dev-<плагин>:<скилл>`.
Кто кого зовёт (стрелка — вызов через пространство имён, не импорт):
```mermaid
flowchart TB
subgraph pipe["av-dev-pipeline — исполнение, требует OpenSpec"]
direction LR
batch["task-batch"] --> tp["task-pipeline"]
tp --> rp["review-pipeline<br/>9 агентов-проходов"]
batch --> rp
end
subgraph pm["av-dev-pm — управление продуктом, владеет docs/"]
direction LR
init["init"] --> tasks["tasks"]
canon["canon"] --> tasks
session["session"] --> tasks
docs["docs"]
end
opsx["opsx:* — внешний плагин:<br/>explore, propose, apply, archive"]
git["av-dev-git: commit"]
tp --> opsx
tp --> git
tp --> docs
tp --> tasks
```
Зависимость **односторонняя: `av-dev-pipeline` знает про `av-dev-pm`, обратно —
нет.** Управление продуктом работает в проекте без конвейера; конвейер без
канона деградирует поразрядно и говорит об этом строкой.
## Канон документов проекта
Все проекты приводятся к одной раскладке — так проще ориентироваться, когда
проектов много, и рядом OpenSpec тоже держит строгую структуру. `CLAUDE.md` плюс
`docs/` (паспорт, архитектура, база, безопасность, конвенции, разведка, ADR,
ревью, задачи) и `openspec/` — **раскладка целиком, роли документов и правило
единственного дома живут одним домом**:
[canon.md](av-dev-pm/skills/canon/references/canon.md). Здесь она не
пересказывается: копия перечня путей уже расходилась с домом, и как раз в
обязательных — в ней не хватало путей, чьё отсутствие `docs.py check` считает
нарушением.
**Отдельного файла-брифа для ревью нет.** Проходы читают документы канона
напрямую; карта «что нужно проходу → где лежит» —
[project-facts.md](av-dev-pipeline/skills/review-pipeline/references/project-facts.md).
Прийти в старый проект и перевести его на канон — `/av-dev-pm:canon`. Канон
версионируется, и проекты повышаются по [журналу
версий](av-dev-pm/skills/canon/references/changelog.md).
## Подключение
Плагин подключается **на уровне проекта**, чтобы был активен у всех, кто
открывает репозиторий. Из терминала, в каталоге проекта:
```bash
cd /path/to/project
# маркетплейс: один раз на проект. --scope project кладёт его
# в extraKnownMarketplaces этого репозитория (см. ниже), без флага — в user
claude plugin marketplace add https://git.vakhrushev.me/av/dev-skills.git --scope project
# плагины: scope обязателен, умолчание у команды — user, а нам нужен project
claude plugin install av-dev-pm@av-dev-skills --scope project
claude plugin install av-dev-pipeline@av-dev-skills --scope project
claude plugin install av-dev-git@av-dev-skills --scope project
```
Те же команды изнутри Claude Code — со слешем: `/plugin marketplace add …`,
`/plugin install … --scope project`. Обе формы дописывают в
`.claude/settings.json` проекта то, что можно внести и руками:
```json
{
"extraKnownMarketplaces": {
"av-dev-skills": {
"source": { "source": "git", "url": "https://git.vakhrushev.me/av/dev-skills.git" }
}
},
"enabledPlugins": {
"av-dev-pm@av-dev-skills": true,
"av-dev-pipeline@av-dev-skills": true,
"av-dev-git@av-dev-skills": true
}
}
```
**При установке в проект, где лежали проектные копии** скиллов и агентов
(`.claude/skills/` — голые `task-pipeline`, `review-pipeline`, `task-batch`
и с префиксом проекта `<проект>-task-pipeline`,
`.claude/agents/<проект>-review-*.md`) — снеси их. Две копии одного скилла
расходятся, и побеждает та, что короче названа.
## Обновление
**Обновление — два шага, и первого мало.** `marketplace update` тянет git-клон
маркетплейса, но снимки плагинов лежат отдельно, в
`~/.claude/plugins/cache/av-dev-skills/<плагин>/<версия>/`, и обновляются только
командой `plugin update`. Один шаг без второго выглядит как «обновил, а ничего не
изменилось» — так и было в первый раз.
```bash
# 0. отправить свои коммиты: до клона доезжает только то, что на origin
git -C /path/to/dev-skills push origin master
# 1. клон маркетплейса
claude plugin marketplace update av-dev-skills
# 2. снимки плагинов — из каталога проекта, где они установлены
cd /path/to/project
claude plugin update av-dev-pm@av-dev-skills --scope project
claude plugin update av-dev-pipeline@av-dev-skills --scope project
claude plugin update av-dev-git@av-dev-skills --scope project
```
**`cd` в проект обязателен, и это не педантизм.** Команда правит запись реестра, а
записей столько, во скольких проектах плагин установлен; за вызов двигается
**одна**. Запущенная не из проекта, она обновит какую-то из них — наблюдалось:
`av-dev-git` стоял в шести проектах, один вызов поднял версию ровно в одном, и не
в том, из которого звали. Проекты обновляются поштучно.
Что стоит и какой версии — одной командой:
```bash
python3 - <<'EOF'
import json, pathlib
d = json.loads(pathlib.Path.home().joinpath(".claude/plugins/installed_plugins.json").read_text())
for name, entries in sorted(d["plugins"].items()):
if "av-dev" not in name:
continue
for e in entries:
print(f"{e['version']:14} {name:30} {e.get('projectPath', e.get('scope', ''))}")
EOF
```
Версия — первые 12 знаков хеша коммита этого репозитория, так что сверяется
глазами с `git rev-parse HEAD | cut -c1-12`. Команда идемпотентна: на уже свежем
плагине скажет `already at the latest version`.
**Изменения применяются после перезапуска Claude Code** — работающая сессия
держит скиллы в контексте и про новый снимок не знает.
## Снятие
Действие, обратное подключению. Актуально для `av-dev-backlog`: плагин устарел,
и с каждого проекта снимается по мере перевода задач на канон `docs/tasks/`.
**Сначала перевод, потом снятие.** Задачи переводит `/av-dev-pm:canon`
(`docs/backlog/``docs/tasks/`). Снять плагин раньше — остаться со старой
раскладкой и без скилла, который её понимает.
```bash
cd /path/to/project
claude plugin uninstall av-dev-backlog@av-dev-skills --scope project
```
Команда правит два места: убирает строку из `enabledPlugins` в
`.claude/settings.json` проекта и запись из реестра
`~/.claude/plugins/installed_plugins.json`. Снимок в
`~/.claude/plugins/cache/av-dev-skills/av-dev-backlog/<версия>/` не трогает — он
общий для всех проектов. Маркетплейс тоже остаётся: `extraKnownMarketplaces`
нужен остальным плагинам.
`--scope project` обязателен по той же причине, что и при установке: умолчание у
команды — user. `cd` в проект обязателен, но здесь ошибка слышна — вызванная не
оттуда, команда откажется словами `is not installed in project scope`, а не
снимет плагин наугад, как это делает `plugin update`.
**Убрать строку из `settings.json` руками — половина дела:** запись в реестре
переживает такую правку, и в инвентаризации проект продолжает числиться. Лечится
той же командой из каталога проекта — она отработает и когда в `settings.json`
уже пусто.
Снялось или нет — видно инвентаризацией из раздела [Обновление](#обновление).
**Применяется после перезапуска Claude Code**, как и обновление.
## Структура репозитория
```
.claude-plugin/marketplace.json манифест маркетплейса
<plugin>/.claude-plugin/plugin.json манифест плагина
<plugin>/skills/<skill>/SKILL.md скилы (авто-обнаружение)
<plugin>/skills/<skill>/references/ что читается по ссылке из скилла
<plugin>/skills/<skill>/scripts/ tasks.py, docs.py
<plugin>/agents/ charter'ы сабагентов
scripts/ проверки репозитория: копии, диаграммы, фронтматтеры
pyproject.toml линтеры скриптов, только для этого репозитория
```
## Проверка скриптов
`tasks.py` и `docs.py` запускаются **где угодно голым `python3` 3.12 без
установки чего-либо** — они лежат рядом со скиллами и работают в любом проекте.
`pyproject.toml` в корне не меняет этого: он живёт только здесь и держит
линтеры, а не зависимости скриптов.
```
uv sync # ставит ruff и pyrefly в .venv, версии прибиты точно
uv run ruff check . # правила; --fix для безопасных починок
uv run pyrefly check # типы
```
Ноль внешних зависимостей охраняется двумя способами: `banned-api` у ruff ловит
частые соблазны по имени, а pyrefly видит окружение, где нет ничего кроме
линтеров, и любой сторонний импорт у него не разрешается. Список запретов —
не перечень мира, настоящий страж второй.
`av-dev-backlog` из проверки исключён намеренно: плагин помечен устаревшим и
живёт до перевода последнего проекта, после чего удаляется целиком. Правки в
замороженный код — риск без выгоды.
## Проверка фронтматтеров
Фронтматтер читает не человек, а загрузчик: по `name` он разрешает вызов, по
`description` решает, звать ли скилл вообще. **Ошибка здесь не выглядит
ошибкой** — тем же способом, что и в диаграммах.
```
uv run python scripts/frontmatter.py # 0 в порядке, 1 расхождение, 3 не тот каталог
```
Ловится три класса:
- **двоеточие с пробелом в описании без кавычек.** Для YAML `: ` внутри
простого скаляра начинает вложенное отображение, так что «конвейер ревью: гейт,
сверка…» — это не текст с двоеточием, а синтаксическая ошибка. Так было
написано часть описаний плагинов, и читались они правильно — замер и разбор
в [DECISIONS.md](DECISIONS.md), решение III;
- **`name`, разошедшееся с именем каталога скилла или файла charter'а.** Вызов
разрешается по каталогу, а сообщение о промахе говорит «нет такого скилла»,
а не «имя не то»;
- **цвет charter'а, не отвечающий его модели.** Цвет кодирует модель, а не роль
прохода — раскладка живёт в
[review-pipeline/SKILL.md](av-dev-pipeline/skills/review-pipeline/SKILL.md),
разделе «Модель по проходу», здесь только её механизация. Держаться вниманием
правило не может: цвет ставится один раз при заведении charter'а, а модель
потом меняется калибровкой.
## Проверка копий правил
«Один факт — один дом» держалось вниманием и трижды не удержалось. Копии всё же
нужны: скелеты канона уезжают в репозиторий проекта и обязаны там что-то
говорить. Значит копия допустима, но **дословная и помеченная**:
```
uv run python scripts/copies.py # 0 сошлось, 1 расхождение, 2 разметка, 3 не тот каталог
```
Разметка — HTML-комментарии, невидимые в отрендеренном markdown:
```
<!-- дом: <id> --> …текст… <!-- /дом: <id> -->
<!-- копия: <id> из <путь к дому> --> …тот же текст… <!-- /копия: <id> -->
```
Идентификатор — буквы, цифры и дефис, и он повторяется в закрывающем маркере.
Строгость нужна ровно затем, чтобы этот абзац сам не объявил дом: `<id>` под
шаблон не подходит.
Сверяется текст между маркерами; ограда блока кода и пустые строки по краям в
сверку не входят. Маркер, уехавший в проект вместе со скелетом, там полезен: он
говорит, что у текста есть дом и правится он там.
Скрипт ловит четыре вещи: копия разошлась с домом (с диффом), копия указывает не
на тот файл, дом остался без копий, разметка сломана. Чего он **не** ловит —
копию, которую забыли пометить: помечать — по-прежнему решение человека.
## Проверка диаграмм
Диаграммы `mermaid` живут исходником в markdown — картинок в репозитории нет.
Синтаксическая ошибка в блоке **не видна при чтении**: текст выглядит
правдоподобно, диff показывает разумную строку, а рендер падает.
```
uv run python scripts/diagrams.py # 0 рендерятся, 1 нет, 3 нет mermaid-cli
```
Рендерит `mmdc` с PATH или `npx --yes @mermaid-js/mermaid-cli`; ни того ни
другого нет — код 3, а не молчаливый успех. Прогон занимает секунды на блок,
поэтому он не в гейте, а в руках того, кто правит диаграмму.
Чего проверка **не** ловит — расхождение диаграммы с прозой вокруг неё. Дословного
соответствия между текстом и графом нет, сличать нечего, и держится это
правилом старшинства, записанным рядом с каждой диаграммой: **в конвейере ревью
старший граф** (он и есть алгоритм планировщика, проза его объясняет), **в
остальных местах старшая проза** (диаграмма там сводка).