CLAUDE.md · git:20260924.1548732 · 2026-09-24 · sha256 5e8a48dfeba5dd34
CLAUDE.md git:20260924.1548732A
Immutable. This exact content never changes and is served at /api/v1/blob/5e8a48dfeba5dd34.
# MAST
Method for Agents, Sessions and Tasks — плагин Claude Code, который разворачивает в чужом
проекте наш способ работы: роадмап с пунктами, worktree на пункт, диспетчер, правила с `paths:`,
архив закрытого.
## Куда смотреть
| Документ | Когда читать |
|---|---|
| [ROADMAP.md](ROADMAP.md) | что осталось сделать |
| [docs/roadmap/done/A-1/SPEC.md](docs/roadmap/done/A-1/SPEC.md) | зачем плагин так устроен, ограничения площадки, состав ядра |
| [docs/roadmap/DONE.md](docs/roadmap/DONE.md) | что уже закрыто |
| [TECH_DEBT.md](TECH_DEBT.md) | что оставлено криво и при каком условии чиним |
| [CHANGELOG.ru.md](CHANGELOG.ru.md) | что меняется для пользователя; закрытый пункт дописывает свои строки в раздел готовящегося релиза |
## Стек
- Markdown — тексты ядра, скиллов и шаблонов, по комплекту на язык в `plugins/<язык>/locales/<язык>/`.
- Python 3 (только stdlib) — скрипты хуков и сторожа́.
- pytest — сторожа́ в `tests/`.
Из одного репозитория собирается **два плагина**: `plugins/en` → `mast` и `plugins/ru` →
`mast-ru`. Язык — это выбор плагина при установке, а не настройка внутри одного.
## Команды
```bash
git config core.hooksPath .githooks # один раз после клонирования
pytest # весь набор
python3 hooks/roadmap_lint.py ROADMAP.md # проверка формата роадмапа
python3 hooks/roadmap_lint.py --ready ROADMAP.md
python3 tools/sync_plugins.py # разложить копии hooks/ по plugins/<язык>/
python3 tools/sync_plugins.py --check # копии отстали от источника? (в pre-commit)
```
`.git/hooks/` не версионируется, поэтому pre-commit едет в `.githooks/` и
подключается этой командой. Не подключил — правку без бампа версии поймает
`tests/test_version_bump.py`, но уже после коммита.
## Живая проверка установки
Маркетплейс-каталог (локальная папка) площадка грузит на месте, без кэша, — он не проверяет
то, что получит пользователь с GitHub. Без push через кэш идёт только git-маркетплейс — его
поднимает скрипт:
```bash
python3 tools/serve_marketplace.py snapshot <каталог> # до установки: копии общих файлов ~/.claude
python3 tools/serve_marketplace.py # до Ctrl+C; --name (по умолчанию mast-local), --port
python3 tools/serve_marketplace.py compare <каталог> # после уборки: 0 отличий — код 0
```
Скрипт собирает bare-репозиторий из текущего дерева, а не из HEAD (`plugins/` и манифест
с другим именем — `ex3del` занято установленным), отдаёт его по smart HTTP через
`git http-backend` (`file://` и `git://` площадка не принимает, dumb HTTP не умеет
shallow-клон) и печатает команды `claude plugin …`: добавить маркетплейс, поставить и убрать
плагин, выключить `mast-ru@ex3del` — всё `--scope local` во временном проекте с `ROADMAP.md`
(иначе ядро не вкладывается). Плагин должен грузиться из `cache/<маркетплейс>/<плагин>/<версия>`,
маркер ядра («## Где что записывать» / «## Where to write things») — в контексте. `compare`
сверяет `settings.json`, `known_marketplaces.json`, `installed_plugins.json`;
автообновление чужих плагинов — не своё, не чинить.
Пробная сессия во временном проекте (`mast start` или `claude --bg --worktree`) доставляет
зависимость `superpowers` с `--scope local` для пути своего worktree; `compare` это ловит,
снимать — `claude plugin uninstall superpowers@claude-plugins-official --scope local` из того
пути (worktree уже удалён — создать каталог заново).
Хуки — живой сессией. `claude --bg` доверяет только точному корню git (родитель не считается) —
временный проект кладётся в доверенный путь, например `/private/tmp/mast-check-new`. Правку
файлов в основной копии фоновой сессии площадка отклоняет сама, раньше PreToolUse, поэтому
хуки на правки проверяются в `claude -p --name …`, а `AskUserQuestion` (в `-p` его нет) —
в `--bg` (A-13).
`claude -p --allowedTools <правило> "<промпт>"` принимает промпт за второе правило, и сессия
стартует без задачи — промпт подаётся через stdin: `echo "<промпт>" | claude -p --allowedTools …`.
`/compact` и `/clear` подаются неинтерактивно: `echo "/compact" | claude -p --resume <id>`. Что
хук `SessionStart` положил в контекст — запись `attachment` `hook_success` с `hookName`
`SessionStart:<source>` в транскрипте, после `compact_boundary`.
Детали прогона — в телах коммитов `8b8f307` и `1a20e4c`.
## Инварианты проекта
- **Плагин не трогает чужое.** Ни `~/.claude/CLAUDE.md`, ни `settings.json` пользователя, ни файлы его проекта без подтверждения. Любая правка существующего файла — только через дифф и вопрос.
- **Ядро в `SessionStart` ≤ 8200 символов** при лимите площадки 10 000. Не влезает — секция уезжает в скилл, а не сокращается до непонятности. Уехала — в ядре остаётся правило одной строкой **и имя скилла в том месте, где оно применяется**: ссылка одним списком в конце не работает, агент не знает, когда её открыть.
- **Два языка равноправны.** Правка текста на одном языке без правки на другом не вливается: сторож локалей сверяет состав файлов и дерево заголовков.
- **Пути внутри плагина — через `${CLAUDE_PLUGIN_ROOT}`.** Никаких `$HOME/.claude/...`: у пользователя плагина такого пути нет. Путь из текста скилла или команды резолвится относительно `plugins/<язык>/`; каждый такой путь проверяет сторож в `tests/test_plugin_manifest.py`.
- **Имя плагина в коде — только из `hooks/plugin_names.py`.** Литерал `mast`/`mast-ru` в хуке расходится с манифестом молча, и пользователь получает ссылку на несуществующую команду или скилл.
- **Числа в «Готово когда» получены замером**, а не переписаны из примера.
- **Плагин самодостаточен, источник один.** Площадка копирует в кэш только содержимое
`plugins/<язык>/` — проверено живьём на установке из маркетплейса, `../../` из плагина ведёт
в пустоту. Тексты языка едут ровно в один плагин и живут только в
`plugins/<язык>/locales/<язык>/` — там и правятся, второй копии нет (сторож в
`tests/test_locales.py`). Код хуков общий на оба плагина: правится **только** в корневых
`hooks/`, копии с пометкой «Сгенерировано» раскладывает `python3 tools/sync_plugins.py`,
а `--check` в pre-commit и сторож в тестах не дают закоммитить отставшую копию или копию
без пометки. Символьная ссылка вместо копии не годится: git на Windows по умолчанию
выкладывает её текстовым файлом, и хук падает с `SyntaxError` (проверено в A-18).
- **Версия растёт вместе с методом и одинакова у обоих плагинов.** Правка `hooks/` или
`plugins/` без бампа — релиз, которого не получит ни один пользователь:
Claude Code обновляет плагин с явной версией только при её росте.
- **Новое правило метода — это пол или потолок?** Пол — инвариант, который проверяет guard
(число в критерии, линт, владение путями). Потолок — «как именно и в каком порядке ходить».
Потолок в ядро и скиллы не вливается: он устареет ровно тогда, когда модель поумнеет,
и его придётся выдирать.