Правила производственного цикла разработки кода для всех проектов Jared.
Тирует задачу (XS / M / L), требует RFC перед кодом для M/L, обязательный
smoke-тест даже на XS, мульти-агентное ревью для M/L, `/security-review` для
L и любых фич с auth/данными, инцидент-лог в blameless-режиме, DOD-чеклист
перед отчётом. Уровни безопасности S1→S3 подключаются инкрементально.
Дополнительно: groom-режим (`/dev-workflow groom`) — проходится по
`private/backlog/BL-*.md`, нормализует названия, выявляет неприбранные
таски, оценивает tier, ловит несоответствия статусов, заполняет пустые
теги/даты. Каждое предложение — с явным подтверждением.
PM-режим (`/dev-workflow dispatch`) — Claude выступает как проджект-
менеджер: декомпозирует задачу на user-level юниты, согласует с
пользователем, раздаёт независимые юниты субагентам в собственных
worktrees, мониторит их параллельно, собирает результат и прогоняет
единое ревью. Триггерится автоматически на пачке из ≥2 независимых
задач (даже XS) или на M/L с честной декомпозицией. Кажд
التثبيت
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
Правила производственного цикла разработки кода для всех проектов Jared.
Тирует задачу (XS / M / L), требует RFC перед кодом для M/L, обязательный
smoke-тест даже на XS, мульти-агентное ревью для M/L, `/security-review` для
L и любых фич с auth/данными, инцидент-лог в blameless-режиме, DOD-чеклист
перед отчётом. Уровни безопасности S1→S3 подключаются инкрементально.
Дополнительно: groom-режим (`/dev-workflow groom`) — проходится по
`private/backlog/BL-*.md`, нормализует названия, выявляет неприбранные
таски, оценивает tier, ловит несоответствия статусов, заполняет пустые
теги/даты. Каждое предложение — с явным подтверждением.
PM-режим (`/dev-workflow dispatch`) — Claude выступает как проджект-
менеджер: декомпозирует задачу на user-level юниты, согласует с
пользователем, раздаёт независимые юниты субагентам в собственных
worktrees, мониторит их параллельно, собирает результат и прогоняет
единое ревью. Триггерится автоматически на пачке из ≥2 независимых
задач (даже XS) или на M/L с честной декомпозицией. Каждый юнит — со
своим «что увидит пользователь»; технический контракт между юнитами
держит PM-Claude, агенты между собой не общаются.
Применяется ТОЛЬКО к разработке кода — скрипты, приложения, MCP-серверы,
SaaS. На продакт-задачи (Notion, Jira, Confluence, тексты, гипотезы) —
не распространяется.
Trigger when: новая задача на разработку кода, появляется /dev-workflow,
"начинаем фичу", "новая фича", "напиши скрипт", "подними MCP", "рефакторинг",
"миграция", "архитектурное изменение", "новый подпроект", "погруми бэклог",
"пройдись по бэклогу", "почисти BL", "оцени таски", "сделай параллельно",
"запусти агентов", "распараллель", "сделай это всё за раз" — или когда
пользователь спрашивает, какой тир у задачи.
Скилл применяется ко всем проектам Jared, где пишем код. Для продакт-задач
(Notion, Jira, Confluence, тексты, оформление гипотез) не применяется — там
работаем как раньше, без церемоний.
Core invariant — BL status transitions (ВСЕГДА)
Это правило выполняется на каждой задаче из бэклога, без исключений. Не
часть pre-flight (тот про сессию целиком) — это про каждый BL отдельно.
При взятии BL в работу (перед первым изменением файла / Edit / Write /
Bash-action, относящимся к задаче):
Прочитать BL целиком (frontmatter + Context + DoD).
Отметить status: in_progress в frontmatter BL-файла.
Добавить (если нет) claimed_by: <branch>@<HH:MM> и claimed_at: <ISO>.
При закрытии BL (после того как DoD выполнен и изменения закоммичены):
Отметить status: done.
Добавить closed: <YYYY-MM-DD>.
Заполнить секцию ## Done или ## Progress с итогом (что сделано,
commits / PR).
Worktree caveat: если работаешь из .claude/worktrees/<name>/, BL-файлы
живут в main checkout (private/backlog/). Используй python3 или sed
через Bash с absolute path к main checkout — Edit/Write упадут из-за
worktree-path хука. Детали в секции «Алгоритм завершения BL» ниже.
Failure mode: если начал работу над BL без отметки in_progress —
ты нарушил invariant. Сразу остановись, проставь статус, продолжай.
Запрещено: «допишу статус в конце», «отмечу при закрытии». Транзишн
planned/open → in_progress происходит до первого изменения, не после.
Этот invariant обязателен потому что:
Параллельные сессии без видимого in_progress приводят к дубликату работы.
Закрытие BL без done — пропадает audit-trail, BL остаётся в planned
навсегда.
Эту дисциплину невозможно обеспечить hook'ом (нет надёжного триггера
«начало работы по BL-N»), поэтому она в скилле как правило для LLM.
Stale-branch trap: запуск команды со ветки, отстающей от main,
даёт wrong результат → диагностируется как баг в коде → часы на
ложный фикс. Реальный кейс 2026-05-17 в ai-job-searcher:
feat/reclassify-imap-bl44 отставала на 4 коммита (RFC 030), bridge-
роли wrongly Weak'нулись (BL-67 / BL-68).
Параллельные сессии + общий бэклог: Jared часто работает в 2-3
сессиях одновременно. Между ними меняется private/backlog/ и
состояние веток. Если новая BL берётся без re-read'а — риск
дублирующей работы или conflict'ов.
Когда запускать
Момент
Branch audit
Backlog audit
Первое касание dev-репо в сессии
✅ обязательно
✅ обязательно
Между задачами в одной сессии (закрыл BL, иду за следующей)
✅ обязательно
✅ обязательно
Перед merge / push / большой prep-командой (prepare, миграция)
✅ обязательно
—
На каждое сообщение
❌ нет
❌ нет
A) Branch audit
git rev-parse --abbrev-ref HEAD # current branch
git status -sb # tree state + ahead/behind tracking
git fetch origin main --quiet
git rev-list --count HEAD..origin/main # # of commits behind main
git log --oneline HEAD..origin/main | head -10 # what's in those commits
git worktree list # other active worktrees
gh pr list --state open --json number,title,headRefName,baseRefName 2>/dev/null
Когда докладывать юзеру (обязательный отчёт):
Ветка отстаёт от main на >0 коммитов → одно сообщение: какая ветка,
на сколько, что в недостающих коммитах (короткими описаниями), и
предложить путь (merge main / rebase / switch to main). Не начинать
основную работу до согласования стратегии.
Working tree содержит правки в файлах, которые меняет open PR →
упомянуть возможный дубликат работы.
Несколько активных worktree'ев → перечислить.
Всё чисто, ветка up-to-date → одной строкой branch: <name>, in sync with main.
B) Backlog audit
ls -lt private/backlog/*.md | head -15 # what changed recently
grep -l "^status: in_progress" private/backlog/*.md 2>/dev/null # active claims
grep -A1 "^status: in_progress" private/backlog/*.md 2>/dev/null # who claimed
Worktree caveat (важно).private/ gitignored — он живёт только в
main checkout, не реплицируется в .claude/worktrees/<name>/. Если
cwd — это worktree (см. git rev-parse --show-toplevel против
git worktree list), то ls private/ вернёт "No such file" — это не
значит, что BL'ов нет.
Правильное действие:
# Определить main checkout (первая строка `git worktree list` — main)
MAIN=$(git worktree list | head -1 | awk '{print $1}')
ls -lt "$MAIN"/private/backlog/*.md | head -15
grep -l "^status: in_progress""$MAIN"/private/backlog/*.md 2>/dev/null
Или гонять команды из main checkout напрямую через absolute path. Тот же
caveat применяется к закрытию BL — см. «Алгоритм завершения BL» ниже.
Когда докладывать юзеру:
BL'ы изменены за последние ~60 минут не моей сессией → перечислить
(другая сессия что-то сделала — стоит понять что, прежде чем
планировать).
BL status: in_progress с claimed_by != моя сессия → flag в отчёте:
«BL-X занята сессией <branch>@<HH:MM>, не беру».
BL status: in_progress с claimed_at > 24h ago без активности →
возможен stale claim, спросить юзера сбросить ли.
C) Claim mechanism (при взятии новой BL)
Identity сессии: <current-branch>@<HH:MM>, например
feat/reclassify-imap-bl44@18:10. Простой формат, человекочитаемый.
Branch уникален per-worktree, время отличает разные сессии на одной
ветке.
Алгоритм взятия BL:
Прочитать BL целиком (включая Plan, DoD, refs).
Грепнуть ^claimed_by: в BL — если уже claimed другой сессией и
claimed_at свежий → не брать, спросить юзера.
Если frontmatter ранее не содержал этих полей — добавить их.
Только после этого начинать первое действие по задаче.
Алгоритм завершения BL:
status: in_progress → done.
Добавить closed: <YYYY-MM-DD>.
claimed_by оставить (полезно для истории/debug — кто закрыл).
Заполнить ## Progress итогом: что сделано, ссылки на commits / PR.
Worktree caveat при закрытии. Если работаешь из .claude/worktrees/<name>/,
файл private/backlog/BL-NN.md физически лежит в main checkout, не в
worktree. Поэтому:
Edit/Write по worktree-relative пути либо упадёт с "file not found",
либо (если хук check_worktree_path.sh настроен) заблокируется при
попытке Edit'ить absolute path в main.
Делать через Bash с absolute path: sed -i '' для замены статуса /
cat >> "$MAIN/private/backlog/BL-NN.md" для дописки Progress.
Хук не трогает Bash, а файл gitignored — это не часть PR, обычное
housekeeping.
Альтернатива — переключить cwd в main checkout, но обычно избыточно
ради одного файла.
Не пропускать закрытие, увидев "no private/" в worktree — это гарантированная
ошибка, а не отсутствие BL.
Если задача abandon'ится посреди работы:
status: in_progress → open.
Удалить claimed_by и claimed_at (либо переписать в last_claimed_by
если хочется audit-trail).
Дописать в ## Progress: почему abandon, что успели.
Анти-паттерны
Молча начать работу с непроверенной ветки.
Взять BL без claim → другие параллельные сессии не увидят что она
занята → дубликат работы.
Между задачами полагаться на in-memory кэш бэклога. Между BL'ами
re-read обязателен, особенно если сессия идёт >1 часа.
При неожиданном результате (prepare wrong, test fails по необъяснимой причине, «фича не работает хотя точно сделана») первая
мысль — диагностировать код. Должно быть наоборот: first thought —
проверить свежесть ветки и состояние бэклога.
Когда не запускать
Сессия про продакт-задачу (Notion, Jira, тексты, гипотезы) — dev-workflow
не применяется в принципе.
Папка без .git/ — branch audit пропускается, backlog audit остаётся
если есть private/backlog/.
Чисто read-only лукапы по коду — необязательно, но желательно при
первом обращении к репо в сессии.
Cost
~10 команд, ~3 секунды, ~500 токенов. Окупается одним предотвращённым
phantom-багом или одним предотвращённым дубликатом работы между
сессиями.
Шаг 0 — классификация
В начале задачи Claude определяет тир. Если неочевидно — называет предполагаемый
тир и спрашивает пользователя, согласен ли он.
Тир
Триггер
Процесс
XS
< 20 строк, багфикс, правка текста/конфига, однофайловое изменение
DOD → код → smoke-тест → self-review (git diff) → показать пользователю → commit
M
новая фича, новый скрипт, 2+ файла, нетривиальная логика, новая интеграция
архитектура, миграция, безопасность, ломающее изменение, новый подпроект, изменение public API
Полный RFC → approve плана → код по частям (feature flag если релевантно) → code-review + /security-review → итог → финальный approve → merge
Правило по умолчанию: сомневаешься между тирами — выбирай выше.
Пачка задач (≥2 независимых): тиры считаются по каждой задаче
отдельно. Дополнительно срабатывает гейт PM-режима (см. Шаг 0.7) —
если задачи реально независимы, Claude предложит распараллелить через
агентов вместо последовательной обработки.
Шаг 0.5 — образ результата (user-level, ДО кода)
Перед RFC, перед кодом, перед техническими деталями — Claude формулирует
конкретизированный образ результата на user-level и согласует его с
пользователем. Это правило важнее RFC: RFC про архитектуру, образ
результата — про UX. Оба нужны, но образ — первый.
Когда обязательно: M / L. Для XS — если задача неоднозначная или
меняет user-visible поведение. Для тривиальных багфиксов / опечаток /
правки конфига без UX-сдвига — пропускаем.
Шаблон:
## Что хочется получить
[Как было] → [Как станет], глазами пользователя.
- Какую команду / действие даёт пользователь.
- Что увидит на выходе (текст, файл, страницу, изменение в Notion / Drive / TSV).
- Какие edge-cases обработаются («если X пустой — увидишь сообщение Y»).
- Что **НЕ** входит в scope (что осталось ручным / отложено / отдельной задачей).
## Куда это положить
[Если правило / процесс — в какой файл; если код — в какой модуль /
команду; если артефакт — в какой каталог.]
Где живёт образ результата:
Если у задачи есть BL-файл — в секции ## Plan или отдельной секции
## Что хочется получить.
Если BL нет — отдельным сообщением в чате с явным «ОК» от пользователя.
Если нет ни BL, ни approval — Claude предлагает завести BL и записать
туда образ, ИЛИ зафиксировать образ в чате перед стартом.
Правило: если что-то не в BL и не в чате с approval — этого не
существует. Continuation-инструкции после /compact, неявные «Step-N»,
«я подумал, нам ещё нужно X» — не источник плана. План — то, что
зафиксировано и одобрено.
Шаг 0.7 — PM-режим (dispatch)
На задачах, которые честно режутся на независимые куски, Claude
меняет роль: не пишет код сам, а выступает как проджект-менеджер.
Декомпозирует, фиксирует с пользователем образ результата по каждому
юниту, раздаёт работу субагентам в собственных worktree, мониторит
параллельно, собирает результат и прогоняет единое ревью.
Это не отдельный pipeline — это надстройка над обычным потоком
Шагов 1–9. Каждый агент внутри своего юнита идёт по тем же правилам
(RFC если M/L, smoke-тест, линтер, ревью). PM-Claude отвечает за
декомпозицию, контракты, интеграцию и финальный DOD.
Гейт — когда режим включается
Автоматически, если выполнено хотя бы одно:
Пачка задач ≥2 штук без видимой зависимости между собой. Тиры
роли не играют — может быть 10 XS, может быть 2 M. Признак
независимости: задачи можно перечислить в произвольном порядке, ни
одна не ждёт результат другой. Примеры: «почини A, B и C», «обнови
README в трёх подпроектах», «закрой эти 5 BL за раз».
Одна M/L задача, которая режется на 2+ независимых юнита.
Признак: каждый юнит имеет собственный наблюдаемый «что увидит
пользователь» и не блокирует остальные. Например: «бэкенд считает
X, фронт показывает X, миграция готовит данные» — три юнита, если
контракт между ними зафиксирован заранее.
Явный вызов: /dev-workflow dispatch, «сделай параллельно»,
«запусти агентов», «распараллель», «сделай это всё за раз».
НЕ включается (последовательный режим быстрее или безопаснее):
Одна XS-задача — даже мелкий агент по времени проиграет прямому
редактированию.
Цепочка зависимых шагов (B нужен результат A) — параллель даст ноль.
Задача с расплывчатым scope — сначала уточняем образ результата,
потом решаем про dispatch.
Юниты сильно пересекаются по файлам — конфликты при сборке съедят
выигрыш. Лучше последовательно.
Гейт всегда озвучен явно. PM-режим не включается молча. Claude
одной фразой говорит: «Вижу N независимых кусков. Параллельно —
управлюсь примерно за время самого долгого, агенты потратят больше
токенов. Последовательно — медленнее, но дешевле и единым стилем.
Параллелим?» Решает пользователь.
Декомпозиция (PM + пользователь, user-level)
Сначала — общий образ результата всей задачи (Шаг 0.5 уже сделан).
Дальше PM-Claude разбивает его на юниты так, чтобы каждый юнит сам был
мини-образом результата. Сумма мини-образов = большой образ.
Что Claude показывает по каждому юниту (3-4 строки, без техники):
Что увидит пользователь после этого юнита — конкретная
наблюдаемая штука. «Команда X теперь выводит Y», «в Notion
появляется поле Z», «при пустой папке — сообщение „пусто"».
Что НЕ входит в этот юнит — явная граница.
Размер — XS / M / L. Сигнал пользователю, сколько ждать.
Зависимости — «независимый» или «ждёт юнит N» одной фразой.
Если хоть где-то стоит «ждёт» — этот юнит из параллельной группы
уходит в очередь.
Что Claude НЕ показывает пользователю (внутренняя кухня PM):
Типы, сигнатуры, имена функций, схемы данных, файлы.
Как именно агенты передают друг другу промежуточный результат.
Это всё попадает в технический бриф агенту, но пользователь в нём не
копается — это лишний шум для PM-а.
Формат экрана декомпозиции (пример на пачке XS):
Образ результата: 3 проекта получают актуальный README с changelog за май.
1. Юнит A — обновить README в `project-alpha` (XS, независимый)
После: в README появится секция «Май 2026» с 4 записями.
НЕ трогаю остальные секции.
2. Юнит B — обновить README в `project-beta` (XS, независимый)
После: то же самое, но с 6 записями.
3. Юнит C — обновить README в `project-gamma` (XS, независимый)
После: то же самое, с 2 записями.
Все три независимы, файлы не пересекаются.
Запускаю параллельно 3 агентов?
Где пользователь решает:
Образ или границы не такие — правит словами, Claude переразбивает.
Хочешь объединить юниты — объединяет.
Хочешь добавить юнит, которого PM не увидел — добавляет.
Один юнит сильно больше остальных → «3 мелких закончатся быстро,
всё равно ждём большой — ок?».
Юниты на самом деле цепляются → «разлепить не получается, делаю
последовательно, объясняю почему».
Между юнитами есть общий контракт (формат данных, который один
готовит, другой читает) → PM говорит про это user-level: «юнит 1
готовит список заказов, юнит 2 его показывает — список должен быть
в одинаковом виде в обоих местах, я это зафиксирую агентам сам».
Детали формата пользователю не показываются.
Dispatch — механика
Запуск. На каждый юнит — один субагент в собственном worktree
(изолированная копия репо через Agent tool с isolation: "worktree").
Агенты друг другу файлы не ломают. Все стартуют одним пакетом
параллельно (множественные tool-calls в одном сообщении), фоном
(run_in_background: true). PM не ждёт каждого — харнес присылает
уведомление, когда агент закончил.
Бриф агенту (моя кухня, пользователю не показывается). У агента
нет доступа к чату — он холодный, как новый сотрудник. Бриф
самодостаточный:
Что должно получиться (тот самый «что увидит пользователь» из
юнита).
Технический контракт (типы, файлы, имена) — задаёт PM, агенты
между собой не договариваются.
DOD юнита — что считается «готово».
Границы — что НЕ трогать (иначе агент полезет в соседний юнит).
Smoke-тест, который агент сам прогоняет перед отдачей.
Куда писать результат в worktree (обычно — обычный коммит в свою
worktree-ветку, PM смерджит).
Агенты не общаются между собой. Все вопросы — через PM. Если два
агента не сошлись по контракту — это ошибка декомпозиции, не их.
Что пользователь видит во время работы — без шума, одна строка на
событие:
Запустил 4 агента в параллель: A, B, C, D.
✅ Юнит C готов — в `project-gamma` README обновлён, 2 записи в «Май».
✅ Юнит A готов — в `project-alpha` README обновлён, 4 записи.
⚠️ Юнит B вернул не то — добавил записи за апрель вместо мая. Переоткрываю.
✅ Юнит D готов — в `project-delta` README обновлён, 3 записи.
✅ Юнит B готов после правки.
Off-spec / залипший агент
Если агент сделал не то / вернул мусор:
PM не правит сам. Иначе размывается роль — потом непонятно, где
чья работа.
Переоткрывает юнит с уточнённым брифом: «вот что было нужно, вот
что ты сделал, разница такая-то». Второй заход, недорого.
Если со второго раза не вышло — PM забирает юнит обратно, делает
сам последовательно, пользователю говорит об этом честно. Не
зацикливается.
Если агент молчит слишком долго (worktree висит) — PM закрывает
агента, переоткрывает юнит. Без терпения.
Сборка
Когда все юниты готовы:
PM по очереди мерджит worktrees обратно в основную ветку.
Конфликт между юнитами — сигнал, что декомпозиция была плохая.
Чинит руками + запись в incidents.md: «такая-то пара юнитов
пересеклась — в следующий раз ловить заранее». Blameless,
чтобы ошибка не повторилась.
Прогоняет общий smoke: всё ли вместе работает, не только по
юнитам в изоляции.
Прогоняет мульти-агентное ревью на собранном диффе (как для M/L
сейчас — Шаг 5).
Финальный approve у пользователя (если есть юниты M/L).
Финальный отчёт пользователю — в его языке:
Все 4 README обновлены. В трёх проектах появилась секция «Май 2026»,
в одном (delta) — заодно поправил битую ссылку, которую агент заметил
по ходу. Закоммитил, запушил. BL-12, BL-13, BL-14, BL-15 → done.
Бюджет и лимиты
Параллельно гоняется максимум столько агентов, сколько юнитов. Если
пользователь говорит «запусти 20» на 5 юнитов — это не ускорит,
лишние не запускаются.
Юнитов много (>7) — пускаются волнами, чтобы не топить контекст PM.
Если стоимость токенов критична — PM явно предупреждает: «4 агента
фоном — примерно в N раз дороже последовательного режима, но
быстрее. Идём?». Решает пользователь.
Чего PM-Claude НЕ делегирует
Чтобы режим не выродился в «Claude нажимает кнопки», PM сохраняет
ownership на:
Образ результата всей задачи. Юниты — это раздробленный продукт,
но продукт всё ещё в голове PM.
Декомпозицию и интерфейсные контракты. Архитектура и границы
юнитов — это PM, не агенты.
Финальную интеграцию и DOD-проверку. Сборка, кросс-юнитный
smoke, ревью собранного диффа.
Решение «параллелим или нет». Гейт остаётся явным.
Коммуникацию с пользователем. Агенты не пишут пользователю
напрямую — всё через PM.
Агенты — это руки. Голова и продукт — PM.
Антипаттерны
«Распараллелим всё». Если юниты не независимы — overhead съест
выигрыш. PM обязан честно говорить «не разлепляется».
«PM пишет код сам, потому что агент тупит». Это нарушение роли.
Либо переоткрытие юнита, либо честный возврат к последовательному
режиму. Микс ломает ответственность.
«Контракт согласован агентами между собой». Никогда. Контракт —
только PM. Если агенты «договариваются» — это значит, PM забыл
зафиксировать формат, и юниты разъедутся.
«Запустили и забыли». PM обязан проверить каждый возвращённый
юнит против его «что увидит пользователь», не просто принять «done»
от агента.
Шаг 1 — RFC (только M/L)
Короткий дизайн-док в PROJECT/rfc/NNN-title.md ДО кода.
## Проблема
Что не работает / чего не хватает. 1–2 предложения.
## Варианты- A: ...
- B: ...
## Выбрано + почему
Вариант X, потому что ...
## Identity & PII (обязательно, если фича касается user data)- ID: формат, источник random (criteria по `feedback_pii_random_ids.md`).
- PII-поля: что считается PII, как помечены в schema (`pii_class`).
- Хранение: где живут (gitignored / encrypted), как gitnoring устроен.
- Логирование: что НЕ должно попасть в логи; redaction policy.
- Удаление: hard delete возможен? Как реализуется right-to-be-forgotten?
- Multi-user-ready: всё ли scope'ится по profile? Что меняется при SaaS-пивоте?
- Если фича не работает с user data — пишем «N/A — фича не касается user data».
## Риски / что может сломаться- ...
## План проверки
Как поймём, что работает (тесты, ручной сценарий, метрика).
Claude пишет RFC и ЖДЁТ явного approve от пользователя перед кодом.
Для XS — RFC не нужен.
Identity & PII секция в RFC обязательна для всех M/L фич. Даже если
ответ «N/A» — это явное решение, зафиксированное. Полные правила —
в ~/.claude/skills/scaffold-project/SKILL.md секция «Identity & PII
rules», или в memory feedback_pii_random_ids.md.
Шаг 2 — код + тесты
Стек тестов:
Язык
Фреймворк
Запуск
JavaScript / Node
node --test (встроено в Node 20+)
node --test в корне проекта
Python
pytest
pip install pytest && pytest
Файлы тестов лежат рядом с кодом: parser.js → parser.test.js,
loader.py → test_loader.py.
Testing pyramid:
Юнит — чистая логика без сети/диска. Пишем много.
Интеграционные — внешние API (MCP, Superset, Jira, Notion). Моки сети, не реальные запросы — иначе флак и квоты.
E2E / ручная — только для критичных прод-сценариев. Описываем чеклистом в RFC, не автоматизируем преждевременно.
Smoke-тест обязателен даже для XS — один простейший тест, доказывающий,
что основная функция вызывается, не падает, возвращает ожидаемый тип.
Ловит 80% поломок рефакторинга за 2 минуты работы.
Шаг 3 — линтеры (только где есть нетривиальный код)
Ставим по мере необходимости, локально в подпроект.
Язык
Инструмент
Конфиг
JavaScript
prettier + eslint (@eslint/js recommended)
минимальный, zero-config
Python
ruff (lint + format в одном)
zero-config
Для bash-скриптов и одноразовых утилит — проверяем глазами, линтер не нужен.
Шаг 4 — pre-commit hook
Появляется только когда в подпроекте есть тесты или линтеры. До этого —
живём без хука.
Когда будет что гонять:
Скрипт в .githooks/pre-commit (коммитим в репо, чтобы пережил сессии).
git config core.hooksPath .githooks локально.
Первая версия — warning-only: прогоняет тесты + линтер для изменённых
файлов, печатает результат, НЕ блокирует коммит. Когда привыкнем —
переключаем в блокирующий режим.
Отдельно: секрет-guard pre-commit hook добавляем при подготовке к
публикации в паблик-репо — блокирует Notion tokens, Google OAuth secrets,
private keys, AWS keys, имя/email автора.
Шаг 5 — мульти-агентное ревью
Тир M
После кода — субагент (general-purpose с фокус-промптом) получает diff.
Фокус:
Читаемость и именование.
Edge cases, которые могли забыть.
Простота — нет over-engineering, абстракций «на вырост».
Соответствие DOD.
Secrets / hardcoded credentials.
Критичные findings Claude исправляет сам. Остальное — summary пользователю.
Claude не коммитит код без ok (для M/L). Для XS — показывает diff и
коммитит, если пользователь заранее дал зелёный свет.
Commit и push — атомарно (2026-05-17)
После каждого git commit Claude сразу же делает git push без
отдельного вопроса. Локальное состояние и GitHub синхронизируются
автоматически. См. правило в проектном CLAUDE.md → раздел «Git push».
Исключения (НЕ пушим автоматически):
pre-commit hook упал или тесты красные → сначала фиксим;
коммит в WIP-состоянии (явно отмечен как промежуточный);
force push в чужую ветку или main/master → требует явного approve.
Если ветки нет в origin — git push -u origin <branch> (set upstream)
автоматически.
Шаг 6 — уровни безопасности (S1/S2/S3)
Безопасность масштабируется инкрементально.
Уровень
Триггер
Что подключаем
S1 — базовый
локальные скрипты, MCP, личные тулы
/security-review для L-тира, secret-detection в code-review, npm audit / pip-audit перед коммитом новых зависимостей, «секреты не в репо»
S2 — pre-prod
SaaS готов к внешнему доступу, появился auth / БД с данными
threat modeling в RFC для фич с auth + данными, SAST (semgrep), OWASP Top 10 чеклист, проверка secrets в CI, auto dependency scanning
S3 — prod с пользователями
публичный SaaS, реальные пользователи
pentest-агент против staging, регулярные прогоны перед релизом, внешний аудит перед платными клиентами / чужими данными / платежами
Дефолт по репо — S1. Переход на S2 — когда появляется первый подпроект
с auth или публичным URL.
Pentest-агент (S3, план на будущее)
Запускается против staging-инстанса (не против кода, не против prod).
Процесс: subagent получает URL + тестовые креды + HTTP/browser тулы → идёт
по OWASP Top 10 чеклисту (auth bypass, injection, XSS, IDOR, CSRF, SSRF,
rate limiting, secrets exposure, broken access control) → каждую попытку
логирует payload → response → classification → возвращает отчёт по severity.
Critical/high — блокеры релиза. Medium/low — в бэклог с дедлайном.
НЕ заменяет: внешний профпентест перед платным продуктом, bug bounty при
масштабе, compliance-аудиты (SOC2, GDPR) если станут требованием.
Реализуем только при переходе на S3, не заранее.
Шаг 7 — инцидент-лог
Когда в прод-приложении что-то сломалось или не заработало с первого раза —
фиксируем в PROJECT/incidents.md:
## YYYY-MM-DD — короткий заголовок**Что произошло**: ...
**Почему (root cause)**: ...
**Что изменили, чтобы не повторилось**: правило / тест / конфиг / refactor.
Blameless — фиксируем причину, не виноватых. Каждый инцидент делает
систему устойчивее: добавленный тест, правило в CLAUDE.md, защита в коде.
Шаг 8 — CI (GitHub Actions)
Добавляется когда первый подпроект выходит в прод (пользователи снаружи).
До этого — overkill.
Минимум на старте:
Прогон тестов на PR.
Прогон линтера на PR.
Блок merge при красном CI.
Дальше — инкрементально по мере роста.
Шаг 9 — документация
Документация = живой контракт поведения системы. Если она не обновляется в
том же коммите, что и код, — она быстро расходится с реальностью, и любой
audit «как должно работать vs как работает» становится бессмысленным.
Базовое правило: код и документация поведения, которое он реализует,
лежат в одном коммите. «Сделаю доку потом» = потом не будет.
Таблица триггеров
Триггер изменения
Что обновляется
Меняется поведение команды / публичной функции / внешнего API
Соответствующий behavioural-контракт в PROJECT/docs/SPEC.md (или эквиваленте per-команду)
Меняется data flow / структура подпроекта / появляется новый модуль
PROJECT/ARCHITECTURE.md
Продуктовая развилка с trade-off'ом (выбран один вариант из нескольких)
Новый ADR в PROJECT/docs/decisions/NNN-title.md (короткий: контекст / решение / последствия)
User-visible изменение (фича / breaking change / deprecation / удаление)
Запись в PROJECT/CHANGELOG.md (формат Keep a Changelog)
Секция в SPEC + миграционная запись в incidents.md если миграция нетривиальна
Меняется setup / onboarding / запуск
PROJECT/README.md
Меняется правило, которое Claude должен помнить между сессиями
PROJECT/CLAUDE.md
Когда документации ещё НЕТ в подпроекте
Если SPEC / ARCHITECTURE / CHANGELOG / ADR-папки в подпроекте ещё не созданы
— сначала спросить пользователя, нужно ли их завести под текущее
изменение. Не создавать молча: пользователь решает, готов ли подпроект к
формальной документационной дисциплине, или это пока ad-hoc разработка.
После создания первого артефакта — он живой, обновляется по триггерам выше
без переспросов.
Что НЕ требует документации
XS-багфиксы, не меняющие поведение (опечатки, рефакторинг без изменений
семантики, тесты, форматирование).
Внутренние имена / приватные хелперы, не вынесенные в публичный контракт.
Эксперименты под feature-флагом до раскатки.
Backlog grooming (/dev-workflow groom)
Отдельный сценарий, не часть основного цикла разработки. Запускается
по триггеру и проходит по private/backlog/BL-*.md текущего проекта,
ищет «грязь» в карточках и предлагает правки. Каждое предложение —
с явным подтверждением, авто-apply'я нет.
Работает ТОЛЬКО над форматом из scaffold-project (frontmatter с
id/title/status/priority/tier/created/tags, body с
Context/Plan/Definition of Done/Progress). Конвенции — в
PROJECT/private/backlog/_README.md каждого проекта.
Триггеры
Команда /dev-workflow groom (с опциональными аргументами).
Фразы: «погруми бэклог», «пройдись по бэклогу», «почисти BL»,
«оцени таски в бэклоге».
Аргументы
Аргумент
Что делает
(без аргументов)
Активные BL: status: open ∪ in_progress. Дефолт.
BL-NN
Только конкретный таск.
--all
Включая done / archived (для разовой массовой нормализации).
--priorities
Дополнительно проставить P0–P3. Без флага приоритеты НЕ трогаются.
Что грумится — детекторы
Каждый детектор формирует отдельную секцию в отчёте. Группируем
по типу проблемы, не по файлам — так быстрее принимать пачками.
1. Названия (нормализация без фанатизма)
Опечатки, обрывки («fix the bug», «TODO migrate», trailing пробелы/
знаки препинания, рассинхрон капитализации).
Сохраняем существующий префикс (Classifier:, Lilia —, RFC-NNN: и т.п.).
Не меняем смысл. Если непонятно, как нормализовать без потери смысла
— попадает в подсекцию «нужна твоя формулировка».
2. Не прогрумлено
Признаки: отсутствует или пуста секция ## Plan, либо отсутствует /
тривиально пустая ## Definition of Done, либо ## Context —
одна-две строки без сути.
Груминг ≠ принятие решений за пользователя. Цель груминга —
подготовить карточку так, чтобы пользователь мог быстро принять
решение по развилкам. Не закапывать развилки под Claude-дефолтами.
Memory: feedback_grooming_no_decisions.md.
Процесс apply:
Разведка фактов — Read/Grep/git/доки по теме таска (упомянутые
модули, соседние BL по refs:, RFC, incidents.md). Не задаём
вопросы пользователю, на которые ответ есть в репо
(feedback_no_redundant_questions.md).
Дописать ## Context — добавить root cause / факты из разведки.
Дописать ## Plan — конкретные шаги. Если по шагу есть
продуктовая развилка — НЕ выбирать вариант, а пометить как
«Шаг N — выбрать подход (см. Open questions Q-K)».
Завести ## Open questions по каждой развилке. Формат на
вопрос:
- **Q1: <вопрос>?**
- (a) <вариант> — pros: …, cons: …
- (b) <вариант> — pros: …, cons: …
- Claude leans toward (b) because …, но ждёт решения юзера.
## Definition of Done — пункты, которые НЕ зависят от
развилок, выписать сразу. Для зависимых — заглушка
«(уточнится после Q-K)». Не дописывать произвольно.
После записи — короткая сводка пользователю в чате:
«Прогрумлено BL-NN. Открытых вопросов: K. Идём дальше?»
Что считается продуктовой развилкой (→ Open questions, НЕ Claude-дефолт):
Как реализовать механику (новое поле в БД vs локальный stamp;
hard delete vs archive vs пометка; opt-in vs always-on).
Когда триггерится (на каждом sync vs отдельная команда; календарные
vs рабочие дни).
Scope (один профиль vs все; ретроактивно vs только future).
Что делать с уже попавшим/сломанным (cleanup-стратегия).
Любой выбор «A vs B vs C» без явного технического выигрыша.
Что МОЖНО решать самому (техническое, не продуктовое):
Где живёт код (file:line).
Имена функций / тестовых кейсов / переменных.
Структура if/else внутри выбранного подхода.
Lint-нормализация.
3. Tier-оценка
Только если задача прогрумлена (есть Plan + DoD) и tier пуст
или вызывает сомнения. Критерии — те же, что в Шаге 0:
XS — < 20 строк, багфикс, правка одного файла/конфига, опечатка,
однофайловое изменение без новой логики.
M — новая фича, новый скрипт, 2+ файла, нетривиальная логика,
новая интеграция (Notion / API / MCP), миграция данных одного типа.
L — архитектура, миграция, безопасность, ломающее изменение,
новый подпроект, изменение public API, фича с auth/PII, multi-step
pipeline, multi-tenant.
Сомневаешься между тирами — выбирай выше.
4. Статусы — несоответствия
status: open, но Progress говорит «✅ закрыто YYYY-MM-DD» / весь Plan
вычеркнут / последний Progress — «merged & deployed» → предлагаем
done + closed: (дату берём из Progress).
status: in_progress, но в Progress нет записей > 14 дней → спрашиваем:
«ещё актуально, на паузе, или archived?». Не закрываем сами.
status: open без активности > 30 дней → то же.
status: done или status: archived без поля closed: → предлагаем
дату из последнего Progress / git-истории / today.
Любой статус, не входящий в {open, in_progress, done, archived}
→ флагуем (старые planned, wip, dropped мигрируем в open /
archived).
5. Теги (если пусты)
Источники для предложений (в порядке убывания силы):
Очевидные ключевые слова из title + Context (classifier,
regex, notion, cron, migration, ats-adapter и т.п.).
Профиль пользователя из refs: (если связано с BL-X про Лилю
→ тег lilia; про Джареда → jared).
Пересечение тегов соседних BL с похожим scope.
Не выдумываем теги без опоры на содержимое — лучше пустой массив, чем
шум.
6. Дата created (если пуста)
Первый источник — git log --diff-filter=A --follow -- <file> →
дата создания файла.
Если git ничего не знает (новый файл, не закоммичен) — today.
Никогда не угадываем «по контексту».
7. Приоритеты (только при --priorities или явной просьбе)
По умолчанию не трогаются — пользователь сам ставит.
С флагом — анализируем dependencies (refs:), наличие deadlines в
Context, business-impact, и предлагаем P0–P3 с reasoning. Каждое
предложение — отдельным подтверждением, не пачкой.
Формат отчёта
Просканировано N активных BL (или N всего, если --all).
Названия (k) — нормализация:
BL-12 "fix the bug in classifier" → "Classifier: fix Deel ACK over-match"
BL-19 "TODO migrate" → нужна твоя формулировка
…
Не прогрумлено (k):
BL-19 "..." нет Plan + DoD
BL-27 "..." Context — 1 строка, нет Plan
…
Tier-оценки (k):
BL-15 → M (новая фича + новая интеграция Notion + 3 файла)
BL-22 → XS (regex в одном файле)
…
Статусы — несоответствия (k):
BL-20 open → done + closed=2026-05-10 (Progress: "merged 2026-05-10")
BL-33 in_progress, тишина 38 дней → спросить: актуально / pause / archived?
…
Теги пусты (k):
BL-22 → [classifier, regex]
BL-29 → [lilia, ats-adapter]
…
Даты пусты (k):
BL-41 → created: 2026-04-22 (git)
…
Приоритеты — пропущены (флаг --priorities не задан).
Если в категории 0 находок — секцию не печатаем. Если вообще
ничего не найдено — отвечаем одной строкой: «Бэклог чистый, грумить
нечего».
Интерактивный режим apply
После сводки:
Применить? [a]ll / [s]elect / by-group / [n]one
all — применить все предложения одним батчем. Перед записью
показываем сводный план (X файлов, Y изменений), ждём финального
«ok».
select — пройтись по каждому предложению y/n.
by-group — применить категорию целиком («все нормализации
названий», «все теги», и т.п.).
n — выйти, ничего не менять.
Для секции «Не прогрумлено» — отдельный поток: спрашиваем по
каждому BL, грумим ли его сейчас. Если да — задаём 2-3 коротких
вопроса (см. выше) и дописываем ## Plan + ## Definition of Done.
Если нет — оставляем пометку в Progress: YYYY-MM-DD — требует груминга (BL-grooming pass).
Все правки — через Edit, по одному файлу за раз. После apply —
короткое подтверждение: «Применено: N изменений в M файлах».
Edge cases
Битый frontmatter / не парсится YAML — отдельная секция
«Сломаны». Показываем, что не парсится, предлагаем минимальный фикс.
Не трогаем без подтверждения.
Конфликт frontmatter ↔ body (status: done, но в Plan живые
чекбоксы) — попадает в «Статусы — несоответствия», не в «Названия».
Legacy-имена (BL-topic-*, RFC-NNN-*, длинные slug'и) — не
переименовываем файлы.id во frontmatter важнее имени. Содержимое
нормализуем как обычно.
done / archived BL — без --all пропускаем целиком, не
шумим. С --all — нормализуем title / теги / closed:, но НЕ
меняем status и НЕ переоцениваем tier.
Пустой бэклог / папка отсутствует — одной строкой: «В проекте
нет private/backlog/BL-*.md, нечего грумить».
Чего groom НЕ делает
Не переименовывает файлы. Только frontmatter и body.
Не меняет смысл задачи. Нормализация title — про опечатки,
капитализацию, чистоту. Не про переписывание сути.
Не выставляет приоритеты по умолчанию — только с --priorities.
Не закрывает активные таски сам — статус-несоответствия
показывает как предложения, ты решаешь.
Не лезет в внешние трекеры (Notion / Jira / GitHub Issues).
Только локальные BL-*.md из формата scaffold-project.
Не интегрируется с CI / pre-commit — это интерактивный
on-demand сценарий, не автоматический хук.
Definition of Done — чеклист перед «готово»
Перед тем как отчитаться, Claude проходит:
Образ результата (Шаг 0.5) был согласован ДО кода — для M/L обязательно, для XS если меняет UX.
PM-режим (Шаг 0.7) — если задача была пачкой ≥2 независимых юнитов или раздавалась агентам: декомпозиция была согласована пользователем; каждый юнит проверен против своего «что увидит пользователь»; собранный дифф прошёл общий smoke + ревью; конфликты при сборке (если были) попали в incidents.md.
Код делает то, что просили (по DOD из TodoWrite).
Smoke-тест (минимум) или юнит/интеграционные тесты (M/L) проходят.
Линтер без ошибок (если настроен).
Diff перечитан (git diff).
Изменения консистентны между файлами.
Для M/L — code-review агент прошёл, критичные findings исправлены.
Секретов в коде нет.
Identity & PII (если фича работает с user data):
- все ID — opaque random (<prefix>_<crypto-random base32 12+>), не PII;
- PII-поля помечены pii_class в schema;
- в логах / ошибках / стек-трейсах — только ID, никогда display_name/email/PII;
- PII отделена от identifier (отдельное поле/файл/колонка);
- папки с PII gitignored или зашифрованы at-rest;
- hard delete возможен (right-to-be-forgotten ready);
- все scope'ится по profile_id (multi-user-ready).
Полные правила — в memory feedback_pii_random_ids.md или
scaffold-project/SKILL.md секция Identity & PII rules.
Документация (SPEC / ARCHITECTURE / CHANGELOG / ADR / README / CLAUDE.md)
обновлена под изменение поведения, если оно было — по таблице из Шага 9.
BL закрыт в трекере (если задача пришла из формального трекера —
private/backlog/BL-NN.md, Jira, Notion Tasks, Linear, etc.):
status: done, closed: <YYYY-MM-DD>, DoD-чекбоксы отмечены,
## Progress дописан с ссылками на commits / PR. Из worktree —
см. caveat в Backlog audit / Алгоритм завершения BL. Игнорировать
"no private/" из worktree — гарантированная ошибка.
Если что-то не ок — исправляем, не спрашивая.
Тон коммуникации с пользователем
Пользователь — продакт, не тех-лид. Это значит:
Объяснения багов и инцидентов: на языке бизнес-логики и продуктовых
side-effects, не на языке implementation. Что сломалось с точки зрения
пользователя продукта, какие видимые последствия (дубли комментариев,
пропущенные письма, неправильный статус), что сделано и какой риск
на будущее. Без stack traces, uid/gid, имён файлов с путями, syscalls,
внутренних модулей. Технические термины уровня "cron", "logs",
"env vars", "OAuth", "permissions", "Docker" — окей, можно. Уровня
EACCES, writeFileSync, atomic-rename, chown -R, uid 1000,
Module._load — нет.
Развилки и решения: формулировать в терминах продуктового impact'а,
не реализации. "Если выберем (A) — фикс никогда не вернётся, но
редеплой 5 минут. Если (B) — переживём пока, починим если опять
всплывёт" — да. "Если (A) — добавим entrypoint script, ENTRYPOINT
вызовет gosu, exec opt-in" — нет.
Не сюсюкать. Пользователь знает, что такое cron, лог, переменная
окружения, OAuth. Метафоры с "роботами", "дневниками", "папками-как-
для-ребёнка" — оскорбительны и теряют сигнал.
Уровень детализации: достаточный, чтобы пользователь понимал
ЧТО произошло и ПОЧЕМУ это важно, но не настолько, чтобы он начал
читать стек. Если просит детали — даю детали; по умолчанию — нет.
Ошибки и стек-трейсы внутри своего workflow: Claude использует их
для диагностики, но в ответе пользователю — пересказывает на
продуктовом языке. Сырой стек показываем, только если пользователь
сам спрашивает про конкретный класс ошибки.