Spec: .wiki/concepts/project-discipline-design.md — four cross-project rules (conventions-over-defaults, master-only, semver-bumping with first-edit-unversioned clause, session-scoped ask-before-push with grant/revoke and force/delete/non-ff exceptions); architecture: single policy skill activated by 'follow project discipline' line in CLAUDE.md template (added by project-bootstrap v1.5.0); 12-task implementation plan tracked in .tasks/project-discipline-skill.md.
24 KiB
title, type, updated
| title | type | updated |
|---|---|---|
| project-discipline — четыре правила работы в проекте | concept | 2026-05-01 |
project-discipline — четыре правила работы в проекте
2026-05-01.
Problem
Дисциплина в работе агента в проекте сейчас держится на двух источниках, которые друг с другом не согласованы:
- Defaults внешних скиллов (superpowers и пр.) — например,
superpowers:brainstormingпишет spec вdocs/superpowers/specs/YYYY-MM-DD-<topic>-design.md. Этот путь зашит в скилл и применяется по умолчанию во всех проектах. - Конвенции конкретного проекта — например, в
claude-skillsspec'и живут в.wiki/concepts/<topic>-design.md, а не вdocs/superpowers/. Эта конвенция нигде явно не объявлена; держится только на том, что текущий агент случайно читает.wiki/CLAUDE.mdдо того, как применить дефолт скилла.
В claude-skills это работает потому что репо плотно дисциплинирован. В других проектах того же пользователя такое не работает: агент по умолчанию пишет в docs/superpowers/, ветвится на feature-branches, забывает bump'ить версии скиллов, и push'ит без подтверждения.
Пользователь хочет четыре правила, действующие во всех его проектах:
- Project conventions > skill defaults — то, что в
CLAUDE.md/.wiki/CLAUDE.md/.tasks/, перекрывает defaults любого скилла. - Master-only — вся работа на главной ветке, никаких feature-branches без явного запроса.
- Versioning discipline — bump version'у на каждом edit'е версионированного артефакта, по semver, в commit-message.
- Commit yes, push no — каждый сеанс стартует с "ask before push"; разрешение на автопуш выдаётся устно в рамках сессии и обнуляется при её завершении.
Текущий механизм передачи кросс-проектных правил — строки-триггеры в CLAUDE.md, активирующие соответствующие скиллы (use superpowers, use project wiki, pull remote before work, и т.д.). project-bootstrap v1.4.0 уже умеет идемпотентный merge новых строк в существующий CLAUDE.md (см. bootstrap-claude-md-merge.md). Эта схема естественно расширяется на новый policy-скилл.
Decision
Два артефакта:
- Новый policy-скилл
project-discipline(skills/project-discipline/SKILL.md, v0.1.0) — кодифицирует все четыре правила, активируется триггеромfollow project disciplineвCLAUDE.md. project-bootstrapv1.4.0 → v1.5.0 (MINOR, добавляет capability) — новая строка вassets/CLAUDE.md.templateсразу послеpull remote before work. Идемпотентный merge в Step 5 переносит её в существующие проекты без ручного edit'а.bootstrap-manifest.mdполучает новую строку дляproject-discipline.
Этот репо (claude-skills) получает trigger'ную строку в свой CLAUDE.md как dogfood.
Почему один скилл, а не четыре
Все четыре правила — про дисциплину работы в проекте, единая тема. Разделение на четыре скилла + четыре строки в CLAUDE.md (use master-only, confirm before push, и т.д.) раздуло бы template и плодит файлы. Если позже какое-то правило отделится в самостоятельный универсальный механизм — выделим его тогда. Сейчас YAGNI.
Почему скилл, а не просто прямые строки в CLAUDE.md template
Прямые строки (work on master only, commit but don't push) тоже сработали бы как триггеры — каждая инструкция в CLAUDE.md имеет высший приоритет. Но:
- Версионирование — правила со временем меняются (например, добавится исключение для force-push). Если они зашиты в template и разосланы по N проектам, обновление = ручной edit в каждом. Скилл со своей версией обновляется централизованно.
- Полнота описания — четыре правила требуют ~150 строк подробной формулировки (что считается push'ем, какие исключения, как выдаётся grant). В
CLAUDE.mdэто не помещается; в скилле — нормальный объём. - Обнаруживаемость —
Skilltool listing показывает скилл с описанием. Прямые строки вCLAUDE.mdагент видит, но не воспринимает как один связанный набор.
Skill behaviour
Activation (description field)
Trigger conditions:
CLAUDE.mdсодержит строкуfollow project discipline— скилл активируется при старте сессии и применяет все четыре правила к остальной работе.- Пользователь явно ссылается на дисциплину: "use project discipline", "соблюди дисциплину", "проектные правила", "что у меня по правилам?".
Скилл сам по себе не выполняет действий и не имеет внешних эффектов; он — policy-документ, читаемый агентом.
Rule 1 — Project conventions override skill defaults
Текст правила в SKILL.md:
До применения defaults любого другого скилла (superpowers, frontend-design, mcp-builder, и т.д.), агент читает в этом порядке:
CLAUDE.mdв корне проекта;.wiki/CLAUDE.md(если существует);.tasks/STATUS.md(если существует).Любой путь, формат, или workflow, явно указанный в этих файлах, перекрывает дефолт скилла.
Конкретные следствия:
- Spec'и / design-документы идут в
.wiki/concepts/<topic>-design.md, не вdocs/superpowers/specs/.- Task tracking — в
.tasks/<slug>.md+STATUS.md(форматusing-tasks), не вdocs/superpowers/plans/или ином inline-формате.- Frontmatter, naming-conventions, log-формат — как описано в
.wiki/CLAUDE.mdпроекта.Если конвенция не указана явно — применяется дефолт скилла.
Почему: в claude-skills это уже работает (поэтому pulling-before-work-design.md лежит в .wiki/concepts/, а не в docs/superpowers/specs/). Цель правила — перенести эту дисциплину в другие проекты пользователя, где она сейчас держится только на удаче.
Rule 2 — Master-only
Текст правила в SKILL.md:
Вся работа идёт на главной ветке репозитория — обычно
master, но если проект используетmain, скилл считаетmainэквивалентом.
- Никаких
git checkout -b feature/fooдля соло-работы.- Sync с remote —
git pull --ff-onlyилиgit pull --rebase. Никаких merge-коммитов для соло-работы.- Если задача реально требует изоляции (большой эксперимент, рискованный refactor с возможностью отката, multi-day работа с промежуточными WIP-коммитами) — агент спрашивает пользователя: "это требует отдельной ветки, ок?" — и ждёт явного разрешения. Без разрешения — на master.
При detached HEAD или нахождении на не-главной ветке (например, после
git checkout) — агент сообщает об этом и спрашивает, нужно ли вернуться на master перед работой.
Почему: соло-разработка с CI/CD не получает выгоды от feature-branches; PR-workflow это overhead для одного человека. Master-only сводит к нулю vocabulary "merge conflict / rebase onto / rebase interactive" в обычном дне.
Rule 3 — Versioning discipline
Текст правила в SKILL.md:
При редактировании любого артефакта с semver-полем агент bump'ит версию перед коммитом по правилам:
- MAJOR (X+1.0.0) — ломает контракт. Переименование скилла, удаление триггеров, изменение layout, удаление публичных функций, breaking change в API.
- MINOR (X.Y+1.0) — добавляет capability без ломки. Новый триггер, новый опциональный шаг, новая публичная функция.
- PATCH (X.Y.Z+1) — wording, clarity, исправление опечаток без изменения поведения.
Bump указывается в commit-message:
feat(<artifact>): … [v<X.Y.Z>]или эквивалент. Точный формат подгоняется под convention'ы проекта (см. Rule 1).Применяется к:
skills/<name>/SKILL.md(frontmatterversion:),package.json("version":),pyproject.toml(version =),Cargo.toml(version =), и любым другим semver-полям.Если артефакт пакуется в
dist/<name>.skill,dist/*.tgzи т.п. — rebuild пакета в том же или следующем коммите. Забытые dist'ы — частая причина деплоя устаревшего бинаря.Первый edit unversioned артефакта, у которого ВОЗМОЖНО semver-поле (новый скилл без
version:, новыйpackage.jsonбез"version":) — агент добавляетversion: 0.1.0(или эквивалент) перед коммитом, не bump'ит существующее.Не применяется к: артефактам без semver-поля и без потенциала его иметь (concept-страницы wiki, README.md, скрипты shell без публичного интерфейса).
Почему: в .wiki/concepts/skill-versioning.md уже описана semver-схема, но (а) она была scoped только на infra-набор скиллов; (б) дисциплина держалась только на текущем агенте. Правило 3 расширяет её на все скиллы в этом репо и на все версионируемые артефакты в любом проекте.
Расширение scope. Концепт-страница skill-versioning.md будет обновлена с пометкой, что после v0.1.0 project-discipline требование версионирования действует на все скиллы, не только infra-subset. Communication-mode скиллы (caveman, ...) и discovery-скиллы (find-skills, active-platform) тоже получают version: поле в frontmatter — это разовый migration, отдельная задача после shipping project-discipline.
Rule 4 — Commit yes, push no (session-scoped)
Текст правила в SKILL.md:
Старт каждой сессии: агент находится в режиме ask-before-push. На каждый
git pushон спрашивает:Готов push'нуть в
<remote>/<branch>(N коммитов: ). Ок?и ждёт явного
yes/да/push/ эквивалента. Без подтверждения — не push'ит.Выдача grant'а в сессии. Пользователь говорит:
- "разреши автопуш" / "allow auto-push" / "автопуш ок" / эквивалент
— после этого агент push'ит без вопросов до конца сессии или до отзыва.
Отзыв grant'а в сессии. Пользователь говорит:
- "отзови автопуш" / "revoke auto-push" / "снова спрашивай" / эквивалент
— агент возвращается в ask-mode.
Конец сессии — состояние не сохраняется. Следующая сессия снова стартует в ask-mode. Это намеренно: grant выдаётся под конкретный текущий контекст (пользователь рядом, осознанно решил что push'ить безопасно), и не должен переживать смену контекста.
Исключения — всегда ask, даже с активным grant'ом:
git push --force/--force-with-lease(перезапись истории);git push origin --delete <branch>(удаление ветки);- push не в текущий tracked upstream (
git push other-remote ...,git push origin other-branch);- push в главную ветку, требующий не-fast-forward (т.е. потребовался бы force).
Логика: grant выдан под обычный fast-forward push в апстрим; всё остальное — отдельный класс операций, требует отдельного решения.
Что считается "push": только команды семейства
git push. Локальные коммиты,git stash push, и т.п. — не push, grant на них не нужен.
Почему: пользователь хочет чтобы каждая сессия начиналась с явного "коммить, но не пуш!" — даже если в прошлой сессии всё было разрешено. Это страховка от "вчера агент думал что все ок, сегодня он же думает что всё ок, и заpush'ил то что не должен был". Persistent grant (файл-флаг в проекте) был бы удобнее но менее безопасен — поэтому намеренно отвергнут.
Out of scope
Скилл не делает:
- Не модифицирует
CLAUDE.md— это работаproject-bootstrap. Скилл — текстовая policy, не tooling. - Не enforce'ит правила через hooks / git hooks / pre-commit — дисциплина агента, не CI. Если пользователь хочет твёрдый enforcement (например,
pre-pushhook, который ломается без явной env-переменной) — это отдельный setup-скилл, не частьproject-discipline. - Не управляет
settings.jsonpermissions — этоupdate-config. Можно представить вариант, в которомgit pushзапрещён по умолчанию черезpermissions.deny: ["Bash(git push:*)"], и Rule 4 его временно ослабляет. Этот вариант отвергнут на v0.1.0: пользователь хочет policy-уровень, не tool-уровень. Если правило Rule 4 окажется недостаточным — вернёмся к идее. - Не проверяет наличие
.wiki//.tasks/— это работаsetup-wiki/setup-tasks/project-bootstrap. Скилл предполагает что layout уже на месте; если.wiki/CLAUDE.mdотсутствует — Rule 1 просто не находит конвенций для override'а и работает как пустой fallback.
Bootstrap integration
assets/CLAUDE.md.template
Текущий вид:
talk like a caveman
use superpowers
use project wiki
use task management system
check across all projects
pull remote before work
we're on Windows
После v1.5.0:
talk like a caveman
use superpowers
use project wiki
use task management system
check across all projects
pull remote before work
follow project discipline
we're on Windows
follow project discipline ставится после pull remote before work и до платформенной строки — потому что:
- Pull остаётся первым в logical order'е (сначала подтягиваем код, потом думаем о правилах).
follow project disciplineлогически суммирует все остальные триггеры, должна стоять близко к их концу.- Платформенная строка — мета-конфиг, всегда последняя.
project-bootstrap SKILL.md изменения
-
Frontmatter:
version: 1.4.0→version: 1.5.0. -
Step 5 — добавить параграф commentary о новой строке (по образцу commentary для
pull remote before work):The
follow project disciplineline activates theproject-disciplineskill, which codifies four cross-project rules: (1) project CLAUDE.md / .wiki/CLAUDE.md / .tasks/ override skill defaults; (2) all work on master/main, no feature branches; (3) version bump on every edit per semver; (4) commit freely, push only after explicit per-session approval. Install the skill on the host ifproject-disciplineis not in~/.claude/skills/; otherwise the trigger is silently dead like any other absent skill. -
Step 5.5 (manifest) — добавить
project-disciplineв таблицу:| Skill | Version | Role | |---|---|---| | `project-bootstrap` | <version> | orchestrator | | `setup-wiki` | <version> | wiki canonical layout | | `setup-tasks` | <version> | tasks canonical layout | | `project-discipline` | <version> | cross-project policy |Манифест читает
version:из frontmatterproject-discipline/SKILL.mdкак для остальных. Если скилл не установлен —unknown, как уже принято.
Idempotent merge — что произойдёт в существующих проектах
Step 5 upgrade-mode (см. bootstrap-claude-md-merge.md) на следующем bootstrap:
- Прочитает существующий
CLAUDE.md. - Не найдёт substring
follow project disciplineв нём. - Покажет user'у diff: "Append 1 missing canonical trigger:
follow project discipline?" - По подтверждению — допишет строку в конец.
Существующий порядок (например, если we're on Windows уже не в конце, а в середине) не пересортировывается — это сделанное решение upgrade-merge'а, чтобы не ломать пользовательские edit'ы.
Cross-impact
| Файл | Изменение |
|---|---|
skills/project-discipline/SKILL.md |
новый, v0.1.0 |
skills/project-discipline/README.md |
новый |
skills/project-bootstrap/SKILL.md |
bump 1.4.0→1.5.0; commentary + manifest row |
skills/project-bootstrap/assets/CLAUDE.md.template |
+1 строка |
skills/project-bootstrap/README.md |
sync (упомянуть новый триггер) |
dist/project-bootstrap.skill |
rebuild |
dist/project-discipline.skill |
новый archive |
~/.claude/skills/project-discipline/ |
install (через install.sh или install.ps1) |
CLAUDE.md (этого репо) |
+1 строка follow project discipline (dogfood) |
.wiki/concepts/skill-versioning.md |
заметка о расширении scope (Rule 3 теперь требует version: на ВСЕХ скиллах) |
.wiki/concepts/project-discipline-design.md |
этот файл |
.wiki/concepts/bootstrap-manifest.md |
regenerate с новой строкой |
.wiki/index.md |
+1 концепт-page link |
.wiki/log.md |
+1 entry decision | project-discipline — четыре правила работы в проекте |
.tasks/project-discipline-skill.md |
новый task-file |
.tasks/STATUS.md |
новый 🔴 active block |
Open questions
- Нужен ли отдельный setup-скилл? По образцу
setup-context7/using-context7. Сейчас — нет:project-disciplineничего не устанавливает, просто policy. Если в будущем добавится tooling-enforcement (git hooks, settings.json overrides) — выделимsetup-project-discipline. - Wide vs narrow Rule 3 scope. Сейчас правило применяется ко всем артефактам с semver-полем. Если окажется что в каких-то проектах семвер реально неуместен (например, исследовательский notebook) — добавим explicit opt-out через
.wiki/CLAUDE.md(# project-discipline: skip versioning). - Migration communication-mode скиллов на
version:. Это побочная работа после shippingproject-discipline. Открывается отдельной задачей в.tasks/. - Отслеживание session-state Rule 4. В текущей имплементации — чисто conversational ("я помню что разрешил"). Если auto-compaction обрезает раннюю часть сессии где был выдан grant — fallback на ask-mode (безопаснее). Это намеренно: лучше переспросить чем накосячить.
References
- bootstrap-claude-md-merge.md — механизм идемпотентного merge, который перенесёт триггер в существующие проекты.
- pulling-before-work-design.md — образец policy-скилла + bootstrap-integration, который этот проект мимикрирует.
- skill-versioning.md — текущая semver-схема, которую Rule 3 расширяет на все скиллы.
- bootstrap-manifest.md — формат манифеста, в который добавляется новая строка.