Files
avandClaude Opus 5 c3e0a6d01f удалён av-dev-backlog: заморозка стоила дороже, чем удаление
Плагин был помечен устаревшим решением Q и жил до перевода jellybit.
Удалён раньше этого срока: условие пережило свою причину.

Заморозка выглядела бесплатной, а платила собой в каждой проверке
репозитория — exclude в pyproject.toml, SKIP_DIRS в copies.py, два абзаца
README, оговорка в описании маркетплейса, чтобы не ловить триггер
«добавь задачу в беклог». Пять исключений ради 706 строк, которые никто
не читает, и каждое надо объяснять всякий раз, когда спрашивают, почему
проверка обходит каталог.

Причина условия отпала раньше названного срока. docs/backlog/ читает не
backlog.py, а av-dev-pm:tasks — adopt.md и адаптер в tasks.py держат ту
же раскладку как вход миграции. Плагин перестал быть единственным, кто
её знает, ещё когда писался adopt, и «живёт до перевода последнего
проекта» с тех пор охраняло пустоту. Перевод jellybit на канон это не
задевает.

Порядок вышел обратный ожидаемому: плагин удалён из маркетплейса, а с
jellybit снят после. Ожидалась ручная чистка enabledPlugins и
installed_plugins.json, но claude plugin uninstall отработал штатно — он
идёт по реестру, а не по манифесту маркетплейса. Раздел «Снятие» в README
переписан с частного случая на общую процедуру, предупреждение заменено
проверенным фактом.

Записи Q и HH получили парные статусы, тема 30 в DECISIONS несёт причины
и три следствия, пункт 5 TODO отмечен, открытый вопрос из REMAINING убран.

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

322 lines
20 KiB
Markdown
Raw Permalink 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-`, имена
**скилов** внутри — короткие. Вызов выходит вида `/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** — работающая сессия
держит скиллы в контексте и про новый снимок не знает.
## Снятие
Действие, обратное подключению.
```bash
cd /path/to/project
claude plugin uninstall <плагин>@av-dev-skills --scope project
```
Команда правит два места: убирает строку из `enabledPlugins` в
`.claude/settings.json` проекта и запись из реестра
`~/.claude/plugins/installed_plugins.json`. Снимок в
`~/.claude/plugins/cache/av-dev-skills/<плагин>/<версия>/` не трогает — он
общий для всех проектов. Маркетплейс тоже остаётся: `extraKnownMarketplaces`
нужен остальным плагинам.
**Удалять из маркетплейса можно и до снятия с проектов.** `uninstall` идёт по
реестру, а не по `marketplace.json`, и снимает плагин, записи о котором в
манифесте уже нет. Проверено на `av-dev-backlog`: удалён из маркетплейса,
снят с jellybit после — команда отработала штатно.
`--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 видит окружение, где нет ничего кроме
линтеров, и любой сторонний импорт у него не разрешается. Список запретов —
не перечень мира, настоящий страж второй.
## Проверка фронтматтеров
Фронтматтер читает не человек, а загрузчик: по `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, а не молчаливый успех. Прогон занимает секунды на блок,
поэтому он не в гейте, а в руках того, кто правит диаграмму.
Чего проверка **не** ловит — расхождение диаграммы с прозой вокруг неё. Дословного
соответствия между текстом и графом нет, сличать нечего, и держится это
правилом старшинства, записанным рядом с каждой диаграммой: **в конвейере ревью
старший граф** (он и есть алгоритм планировщика, проза его объясняет), **в
остальных местах старшая проза** (диаграмма там сводка).