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.
267 lines
24 KiB
Markdown
267 lines
24 KiB
Markdown
---
|
||
title: "project-discipline — четыре правила работы в проекте"
|
||
type: concept
|
||
updated: 2026-05-01
|
||
---
|
||
|
||
# project-discipline — четыре правила работы в проекте
|
||
|
||
_2026-05-01._
|
||
|
||
## Problem
|
||
|
||
Дисциплина в работе агента в проекте сейчас держится на двух источниках, которые друг с другом не согласованы:
|
||
|
||
1. **Defaults внешних скиллов** (superpowers и пр.) — например, `superpowers:brainstorming` пишет spec в `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`. Этот путь зашит в скилл и применяется по умолчанию во всех проектах.
|
||
2. **Конвенции конкретного проекта** — например, в `claude-skills` spec'и живут в `.wiki/concepts/<topic>-design.md`, а не в `docs/superpowers/`. Эта конвенция нигде явно не объявлена; держится только на том, что текущий агент случайно читает `.wiki/CLAUDE.md` до того, как применить дефолт скилла.
|
||
|
||
В `claude-skills` это работает потому что репо плотно дисциплинирован. В **других** проектах того же пользователя такое не работает: агент по умолчанию пишет в `docs/superpowers/`, ветвится на feature-branches, забывает bump'ить версии скиллов, и push'ит без подтверждения.
|
||
|
||
Пользователь хочет четыре правила, действующие во всех его проектах:
|
||
|
||
1. **Project conventions > skill defaults** — то, что в `CLAUDE.md` / `.wiki/CLAUDE.md` / `.tasks/`, перекрывает defaults любого скилла.
|
||
2. **Master-only** — вся работа на главной ветке, никаких feature-branches без явного запроса.
|
||
3. **Versioning discipline** — bump version'у на каждом edit'е версионированного артефакта, по semver, в commit-message.
|
||
4. **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](bootstrap-claude-md-merge.md)). Эта схема естественно расширяется на новый policy-скилл.
|
||
|
||
## Decision
|
||
|
||
Два артефакта:
|
||
|
||
1. **Новый policy-скилл `project-discipline`** (`skills/project-discipline/SKILL.md`, v0.1.0) — кодифицирует все четыре правила, активируется триггером `follow project discipline` в `CLAUDE.md`.
|
||
2. **`project-bootstrap` v1.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` это не помещается; в скилле — нормальный объём.
|
||
- **Обнаруживаемость** — `Skill` tool 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, и т.д.), агент читает в этом порядке:
|
||
>
|
||
> 1. `CLAUDE.md` в корне проекта;
|
||
> 2. `.wiki/CLAUDE.md` (если существует);
|
||
> 3. `.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` (frontmatter `version:`), `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 коммитов: <subjects>). Ок?
|
||
>
|
||
> и ждёт явного `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-push` hook, который ломается без явной env-переменной) — это отдельный setup-скилл, не часть `project-discipline`.
|
||
- **Не управляет `settings.json` permissions** — это `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`
|
||
|
||
Текущий вид:
|
||
|
||
```markdown
|
||
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:
|
||
|
||
```markdown
|
||
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 discipline` line activates the `project-discipline` skill, 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 if `project-discipline` is not in `~/.claude/skills/`; otherwise the trigger is silently dead like any other absent skill.
|
||
|
||
- Step 5.5 (manifest) — добавить `project-discipline` в таблицу:
|
||
|
||
```markdown
|
||
| 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:` из frontmatter `project-discipline/SKILL.md` как для остальных. Если скилл не установлен — `unknown`, как уже принято.
|
||
|
||
### Idempotent merge — что произойдёт в существующих проектах
|
||
|
||
Step 5 upgrade-mode (см. [bootstrap-claude-md-merge.md](bootstrap-claude-md-merge.md)) на следующем bootstrap:
|
||
|
||
1. Прочитает существующий `CLAUDE.md`.
|
||
2. Не найдёт substring `follow project discipline` в нём.
|
||
3. Покажет user'у diff: "Append 1 missing canonical trigger: `follow project discipline`?"
|
||
4. По подтверждению — допишет строку в конец.
|
||
|
||
Существующий порядок (например, если `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:`.** Это побочная работа после shipping `project-discipline`. Открывается отдельной задачей в `.tasks/`.
|
||
- **Отслеживание session-state Rule 4.** В текущей имплементации — чисто conversational ("я помню что разрешил"). Если auto-compaction обрезает раннюю часть сессии где был выдан grant — fallback на ask-mode (безопаснее). Это намеренно: лучше переспросить чем накосячить.
|
||
|
||
## References
|
||
|
||
- [bootstrap-claude-md-merge.md](bootstrap-claude-md-merge.md) — механизм идемпотентного merge, который перенесёт триггер в существующие проекты.
|
||
- [pulling-before-work-design.md](pulling-before-work-design.md) — образец policy-скилла + bootstrap-integration, который этот проект мимикрирует.
|
||
- [skill-versioning.md](skill-versioning.md) — текущая semver-схема, которую Rule 3 расширяет на все скиллы.
|
||
- [bootstrap-manifest.md](bootstrap-manifest.md) — формат манифеста, в который добавляется новая строка.
|