24 KiB
06. Интеграция с Plane
Назначение: описать, как использовать Plane так, чтобы он стал «витриной» процесса для человека (заказчика, менеджера, наблюдателя), при этом источником правды оставался Git. Здесь — иерархия объектов, шаблоны Work Item'ов, custom fields, webhooks, MCP-инструменты, сценарии реакции на события.
Простым языком
Вы хотите видеть весь процесс в одном месте — в Plane: какие фичи, какие фазы, что на каком этапе, кто (какой агент) сейчас работает, какие у задачи документы, ссылки на код. Чтобы новые задачи можно было заводить из Plane (или попросить агента завести), а ковыряться в репозитории не приходилось.
Именно так и устроено:
- Workspace = ваша компания.
- Project = один продукт / один репозиторий (например,
fr24-noisemap). - Work Item типа Phase = группа фич в одном релизе (опционально, для крупных проектов).
- Work Item типа Feature = одна фича / задача с самостоятельной ценностью.
- Подзадачи Work Item'а = 7 шагов производственного процесса (Анализ → Архитектура → Дизайн → Разработка → Review → Тест → Внедрение).
В каждой подзадаче — статус (To Do / In Progress / Awaiting Approval / Done / Blocked), ссылка на коммиты/PR, прикреплены или связаны артефакты из Git (через ссылки на docs/work-items/<id>/...). Вы открываете Work Item — и видите полную картину: ТЗ, дизайн, код, отчёт о тестах, deploy log.
Согласование БТ, ТЗ, дизайна — через комментарии и reactions (:approved:). Завести новую фичу — через кнопку «New Work Item» в Plane или через комментарий «Аналитик, заведи фичу: …» агенту-Analyst (если включён MCP).
Иерархия объектов
Workspace (ваша компания)
└── Project (= один репозиторий)
└── Work Item (Phase — опционально)
└── Work Item (Feature)
├── Subtask: Анализ
├── Subtask: Архитектура
├── Subtask: Дизайн UI/UX
├── Subtask: Разработка
├── Subtask: Code Review
├── Subtask: Тестирование
└── Subtask: Внедрение
Ограничение Plane: глубина вложенности — 1 уровень. То есть Phase → Feature → Subtask не работает: Subtask не может иметь свой Subtask.
Решение: этапы производственного процесса висят как Subtask на Feature (не на Phase). Phase же — просто группирующая «папка» с привязанными Feature'ами через parent_id или label.
Типы Work Item
В Plane создаются (через UI или API) следующие типы (через module или cycle или через label type:*):
| Тип | Когда используется | Имеет подзадачи производственного процесса? |
|---|---|---|
Feature |
Самостоятельная фича с измеримой ценностью | Да (7 субтасков) |
Bug |
Найденный дефект, требующий исправления | Да (но обычно урезано: Анализ → Разработка → Review → Тест → Внедрение) |
Tech-debt |
Технический долг | Да (полный цикл, либо урезано) |
Phase |
Группа Feature'ов в один релиз | Нет (управление через привязки) |
Spike |
Исследование / прототип / RFC | Свободная форма (без QG-конвейера) |
Decomposition |
Метка задачи, разбитой на дочерние | Нет (после декомпозиции закрывается, дальше работают дочерние) |
Qg-override |
Аварийный обход QG | Нет (особый процесс) |
Incident |
Инцидент в проме | Свободная форма + обязательный postmortem |
Custom fields на Work Item (Feature)
Plane поддерживает custom properties через настройки workspace. Включить:
| Field | Type | Описание |
|---|---|---|
business_value |
text | Краткое «зачем», 1–3 предложения |
success_metric |
text | Измеримая метрика успеха |
repo_branch |
url | Ссылка на ветку в Git |
repo_pr |
url | Ссылка на PR (заполняется CI после открытия) |
repo_artifacts_path |
text | docs/work-items/<plane-id>/ — путь к папке артефактов |
phase_id |
reference | Ссылка на родительскую Phase (опционально) |
qg_status |
select | По текущему этапу: qg-1, qg-2, qg-3, qg-4, qg-5, qg-6, qg-7, qg-final, qg-blocked |
tokens_spent_usd |
number | Накопительная стоимость LLM-вызовов (CI обновляет) |
lead_time_hours |
number | От создания до закрытия (CI обновляет) |
ui_affected |
boolean | Затрагивает UI (определяется на этапе Анализа) |
breaking_change |
boolean | Содержит breaking change |
Лейблы (labels)
Используются для маршрутизации и фильтрации. Зарезервированы префиксы:
area:*— область кодовой базы:area:frontend,area:backend,area:infra,area:data,area:design-system.type:*— тип работы:type:feature,type:bug,type:tech-debt,type:spike,type:phase.priority:*— приоритет:priority:p0(urgent) …priority:p3(low).stage:*— текущий этап производственного процесса:stage:analysis,stage:arch,stage:design,stage:dev,stage:review,stage:test,stage:deploy,stage:done. Меняется автоматически при прохождении QG.back-to:*— задача возвращена на более ранний этап:back-to:analysis,back-to:arch,back-to:dev. Метка ставится агентом-Reviewer/Tester при request-changes.skip:*— этап пропущен с обоснованием:skip:not-applicable,skip:overridden.block-merge— стоп-кран для деплоя.escalation:*— нужна человеческая помощь:escalation:meeting-needed,escalation:human-needed,escalation:owner-approval.incident:*— инциденты:incident:prom-deploy,incident:rollback-failed.bug:found-by-qa,bug:found-on-prom— источник бага.arch:major-change— крупное архитектурное изменение, требующее согласования.
Шаблон описания Work Item (Feature)
При создании Feature заказчиком — никаких обязательных секций (намеренно: чтобы порог входа был низким). Достаточно description ≥150 символов.
После QG-0 webhook автоматически перезаписывает Feature.description в шаблон:
## Запрос от заказчика
<копия исходного description>
## Артефакты
- 📋 BRD: `docs/work-items/<id>/01-brd.md` (создаётся Analyst'ом)
- 📐 ТЗ: `docs/work-items/<id>/02-trz.md`
- ✅ Acceptance: `docs/work-items/<id>/03-acceptance-criteria.md`
- 🧪 Test Plan: `docs/work-items/<id>/04-test-plan.yaml`
- 🏛 ADR: `docs/work-items/<id>/06-adr/`
- 🎨 Design: `docs/work-items/<id>/11-design/` (если ui_affected)
- 👀 Code Review: `docs/work-items/<id>/12-review.md`
- 🧾 Test Report: `docs/work-items/<id>/13-test-report.md`
- 🚀 Deploy Log: `docs/work-items/<id>/14-deploy-log.md`
## Связи
- Branch: <ссылка на ветку>
- PR: <добавится после открытия Developer'ом>
## Прогресс
- [ ] QG-1: Анализ approved
- [ ] QG-2: Архитектура утверждена
- [ ] QG-3: Дизайн approved (если применимо)
- [ ] QG-4: CI зелёный
- [ ] QG-5: Code Review approved
- [ ] QG-6: Тесты зелёные на preview
- [ ] QG-7: Test smoke + approve для prom
- [ ] QG-final: Prom стабилен + final approve
Чек-боксы автоматически обновляются CI через Plane API.
Шаблон каждой подзадачи
При создании Feature webhook автоматически создаёт 7 подзадач (или 6, если без UI):
Subtask: «Анализ» (stage:analysis)
## Цель
Сформировать BRD, ТЗ, Acceptance Criteria, Test Plan по запросу заказчика.
## Owner
Agent: analyst (Sonnet 4.6)
## DoD
- [ ] `01-brd.md` создан и проходит spec-linter
- [ ] `02-trz.md` создан и проходит spec-linter
- [ ] `03-acceptance-criteria.md` создан
- [ ] `04-test-plan.yaml` валиден по JSON-Schema
- [ ] Все REQ покрыты AC и TC (req-coverage check зелёный)
- [ ] `:approved:` от стейкхолдера
## SLA
24 часа на одну итерацию.
## Артефакты
docs/work-items/<id>/01-brd.md
docs/work-items/<id>/02-trz.md
docs/work-items/<id>/03-acceptance-criteria.md
docs/work-items/<id>/04-test-plan.yaml
Subtask: «Архитектура» (stage:arch)
## Цель
Зафиксировать архитектурные решения по ТЗ (ADR), обновить C4-диаграммы, требования к инфраструктуре, данным, UI.
## Owner
Agent: architect (Opus 4.7)
## DoD
- [ ] Хотя бы один ADR создан и проходит adr-linter
- [ ] Все REQ из ТЗ покрыты ADR (req-coverage check)
- [ ] C4-диаграммы рендерятся
- [ ] `07-infra-requirements.md`, `08-data-requirements.md` созданы
- [ ] `09-ui-requirements.md` создан, если ui_affected: true
- [ ] `10-tech-risks.md` создан
## SLA
24 часа.
## Артефакты
docs/work-items/<id>/06-adr/
docs/work-items/<id>/07..10-*.md
(И аналогично для остальных 5 подзадач — см. 01_production_process.md.)
Webhooks
Plane → Orchestrator (HTTP endpoint, ~300 строк Python). События:
| Событие Plane | Реакция Orchestrator |
|---|---|
work_item.created (type=Feature) |
1) Проверить QG-0; 2) Создать ветку feature/<id>-<slug> в Git; 3) Создать 7 подзадач (или 6 без UI на старте — Analyst пометит); 4) Создать docs/work-items/<id>/00-business-request.md с копией description; 5) Запустить агента analyst. |
work_item.updated (status → To Do, Subtask «Анализ») |
Если ещё не запущен — запустить analyst. |
comment.created на Work Item с :approved: |
Проверить роль автора. Если Stakeholder — перевести соответствующую подзадачу в done, запустить QG, перейти к следующей. |
work_item.updated (status → Done, Subtask «Анализ») |
Запустить QG-1. При зелёном — запустить architect. |
work_item.updated (status → Done, Subtask «Архитектура») |
QG-2. При зелёном — если ui_affected:true — запустить designer, иначе — закрыть подзадачу «Дизайн» как skip:not-applicable и запустить developer. |
comment.created на Work Item с :break-glass: |
Override-процедура. Только от Owner. Логировать в qg-overrides.log. |
work_item.updated (priority → urgent) |
Поднять приоритет в очереди агентов. |
Forge (GitHub/Gitea) → Orchestrator. События:
| Событие Forge | Реакция |
|---|---|
pull_request.opened (label stage:dev) |
Связать PR с Plane Work Item (по <plane-id> в имени ветки). Проставить repo_pr поле. |
check_suite.completed (CI на PR) |
Если зелёный + лейбл stage:dev → запустить QG-4. При успехе — запустить reviewer. |
pull_request_review.submitted (status APPROVED) |
QG-5. При успехе — лейбл stage:test, запустить tester. |
pull_request_review.submitted (status REQUEST_CHANGES) |
Лейбл back-to:dev, статус подзадачи «Разработка» → in_progress. |
pull_request.merged |
Запустить deployer (deploy-test). |
release.published (tag v*) |
Запустить deploy-prom workflow при наличии approve. |
MCP для Plane
В каждом проекте .openclaw/mcp.json подключает Plane MCP-сервер:
{
"mcpServers": {
"plane": {
"command": "npx",
"args": ["-y", "@plane/mcp-server"],
"env": {
"PLANE_API_TOKEN": "${PLANE_API_TOKEN}",
"PLANE_WORKSPACE_SLUG": "${PLANE_WORKSPACE}",
"PLANE_BASE_URL": "${PLANE_BASE_URL}"
}
},
"forge": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GH_TOKEN}"
}
},
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp"]
}
}
}
Если официального Plane MCP-сервера ещё нет на момент запуска — собрать тонкую обёртку (~150 строк Python) над Plane REST API, экспонирующую нужные действия как MCP-tools:
plane_get_work_item,plane_update_status,plane_add_comment,plane_search_items,plane_create_issue,plane_set_label. Контракт MCP даёт стабильное имя; реализация — наша.
Доступные MCP-tools (минимальный контракт)
| Tool | Назначение | Доступен агентам |
|---|---|---|
plane_get_work_item(id) |
Получить Work Item с описанием, статусом, лейблами, подзадачами, комментариями | All |
plane_search_items(query, project) |
Найти Work Item по тексту/лейблу | Analyst, Architect, Reviewer |
plane_update_status(id, status) |
Сменить статус Work Item / подзадачи | All |
plane_set_label(id, label) |
Поставить/снять лейбл | All |
plane_add_comment(id, body) |
Оставить комментарий | All |
plane_get_comments(id, since?) |
Прочитать комментарии (с фильтром по дате) | All |
plane_check_reaction(id, emoji, role) |
Проверить, есть ли reaction указанного типа от пользователя с указанной ролью | Orchestrator, agents |
plane_create_issue(parent_id, type, title, body) |
Создать дочерний Work Item (для багов, декомпозиции) | Analyst, Tester |
plane_link_pr(work_item_id, pr_url) |
Прикрепить ссылку на PR в custom field | Developer, Orchestrator |
plane_set_custom_field(id, field, value) |
Обновить custom field | Orchestrator (через CI) |
Reactions как «штамп»
В Plane через UI или MCP можно ставить reactions на комментарии. Договорные реакции:
| Reaction | Семантика | Кто ставит |
|---|---|---|
:approved: |
Одобряю переход на следующий этап | Stakeholder / Owner |
:rejected: |
Возврат на доработку (с комментарием почему) | Stakeholder / Reviewer |
:break-glass: |
Аварийный override QG | Owner |
:final-approved: |
Финальный approve после деплоя в prom | Stakeholder |
:duplicate: |
Дубль другой задачи | Analyst |
:wont-fix: |
Не будет реализовано (с комментарием почему) | Stakeholder |
Orchestrator через plane_check_reaction собирает reactions и принимает решения о переходе.
Создание новой задачи: 3 пути
Путь 1: через UI Plane (для человека).
Заказчик нажимает «New Work Item», заполняет title и description, выбирает project и priority. Webhook на event work_item.created запускает QG-0 → создание ветки и подзадач.
Путь 2: через комментарий «Analyst»-агенту в Plane (тоже для человека, но более «разговорно»).
В любом проекте есть Work Item с лейблом bot:analyst-inbox. Заказчик оставляет туда комментарий: «Хочу новую фичу: чтобы на карте отображалась частота полётов». Plane MCP запускает Analyst в режиме intake, который через plane_create_issue создаёт новый Feature, перепосылает description, и стартует QG-0.
Путь 3: через CLI / API (для автоматизаций).
plane create-work-item --project fr24-noisemap --title "..." --description "...". Используется для bulk-импорта или интеграций.
Все три пути приходят в одну точку: создание Feature → webhook → QG-0 → ветка + 7 подзадач.
Прикрепление артефактов к Work Item
Plane умеет прикреплять файлы, но это не наш путь: артефакты живут в Git. Вместо вложений — ссылки в description Work Item на файлы в Git (через permalink на коммит).
Webhook каждый раз при коммите в ветку обновляет description Feature, чтобы ссылки указывали на актуальный SHA:
- 📋 BRD: [docs/.../01-brd.md@a1b2c3d](https://gitea.example.com/.../docs/.../01-brd.md?at=a1b2c3d)
Так в Plane всегда виден актуальный артефакт, без ручных загрузок.
Дополнительно: Plane умеет рендерить markdown в comments — поэтому ссылка прямая на raw-файл рендерит preview прямо в Plane.
Просмотр документации в Plane
Агент analyst при изменении ТЗ автоматически:
- Делает коммит с новой версией
02-trz.md. - Постит в комментарии Work Item: «Обновил ТЗ. Diff: <ссылка на forge-compare>».
- (опц.) Прикладывает inline-diff в комментарий через
plane_add_comment.
Так заказчик видит изменения прямо в Plane, не открывая Git.
Согласование, изменение, заведение через Plane
Согласование:
- Reaction
:approved:или:rejected:(с обязательным следующим комментарием объясняющим причину) на соответствующей подзадаче.
Изменение:
- Комментарий на Work Item: «Хочу изменить REQ-F-3 — теперь ...» . Analyst видит, делает коммит с новой версией ТЗ, пингует стейкхолдера на новый approve.
- Если изменение крупное (меняется scope) — Analyst может предложить декомпозировать: «Это уже не правка текущей задачи, а новая. Разрешите завести Feature Y?»
Заведение новой:
- См. «Путь 1/2/3» выше.
Дашборды для человека
Plane умеет строить Views и Dashboards. Рекомендуемые:
- Текущая работа (для каждого юзера): мои Work Item'ы, в которых я Stakeholder, и в которых статус =
awaiting-approval(нужен мой apprve). - Витрина проекта (на проект): список всех активных Feature, разбитый по
stage:*, цветной поpriority:*, с показомtokens_spent_usdиlead_time_hours. - Phase board (если используются фазы): все Feature внутри Phase, разбитые по статусу.
- Backlog: все Feature в статусе
backlog/To Do, отсортированные по приоритету иbusiness_value. - Health: алёрты — задачи в
Blockedдольше 24ч, задачи сtokens_spent_usd> порога, задачи с количествомback-to:*> 2.
Audit и compliance
Каждое изменение Work Item Plane логирует автоматически. Дополнительно Orchestrator пишет в свой Postgres-журнал:
- запуски агентов (when, agent, model, tokens, cost)
- QG-проверки (when, gate, verdict, reason)
- Override-события
- Reaction-events
Это даёт полный аудит-трейл: «кто (агент) что сделал, когда и почему».
Антипаттерны интеграции с Plane
- ❌ Хранить ТЗ как вложение к Work Item. Только в Git.
- ❌ Менять статусы вручную, обходя webhook'и. Орекстратор — единственный, кто двигает по конвейеру.
- ❌ Делать «несколько подзадач Анализа». Подзадач ровно 6/7 типовых; декомпозиция — через дочерние Feature.
- ❌ Использовать Plane как чат. Длинные обсуждения — голосом, итог — в комментарии-резюме.
- ❌ Хранить секреты Plane API в репо. Только в
.envи в секретах CI. - ❌ Запускать агентов напрямую из Plane UI. Это всегда через Orchestrator.