- TaskDetail: hide Approve/Reject buttons in auto mode, show "Автопилот активен" badge
- TaskDetail: execution_mode persisted per-task via PATCH /api/tasks/{id}
- TaskDetail: loadMode reads DB value, falls back to localStorage per project
- TaskDetail: back navigation preserves status filter via ?back_status query param
- ProjectView: toggleMode now persists to DB via PATCH /api/projects/{id}
- ProjectView: loadMode reads project.execution_mode from DB first
- ProjectView: task list shows 🔓 badge for auto-mode tasks
- ProjectView: status filter synced to URL query param ?status=
- api.ts: add patchProject(), execution_mode field on Project interface
- core/db.py, core/models.py: execution_mode columns + migration for projects & tasks
- web/api.py: PATCH /api/projects/{id} and PATCH /api/tasks/{id} support execution_mode
- tests: 256 tests pass, new test_auto_mode.py with 60+ auto mode tests
- frontend: vitest config added for component tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 KiB
ADR: Auto Mode — полный автопилот (KIN-012)
Дата: 2026-03-15 Статус: Accepted Автор: architect (KIN-012)
Контекст
Задача: реализовать два режима исполнения пайплайнов:
- Auto — полный автопилот: pipeline → auto-approve → auto-followup → auto-rerun при permission issues → hooks. Без остановок на review/blocked.
- Review — текущее поведение: задача уходит в статус
review, ждёт ручного approve.
Что уже реализовано (анализ кода)
1. Хранение режима — core/db.py
projects.execution_mode TEXT NOT NULL DEFAULT 'review'— дефолт на уровне проектаtasks.execution_mode TEXT— nullable, переопределяет проект- Миграции добавляют оба столбца к существующим БД
2. Приоритет режима — core/models.py:get_effective_mode()
task.execution_mode > project.execution_mode > 'review'
Вычисляется один раз в начале run_pipeline.
3. Auto-approve — agents/runner.py:run_pipeline() (строки 519–536)
if mode == "auto":
models.update_task(conn, task_id, status="done")
run_hooks(conn, project_id, task_id, event="task_auto_approved", ...)
else:
models.update_task(conn, task_id, status="review")
4. Permission retry — agents/runner.py:run_pipeline() (строки 453–475)
if mode == "auto" and not allow_write and _is_permission_error(result):
run_hooks(..., event="task_permission_retry", ...)
retry = run_agent(..., allow_write=True)
allow_write = True # propagates to all subsequent steps
- Срабатывает только в auto режиме
- Ровно 1 попытка retry на шаг
- После первого retry
allow_write=Trueсохраняется на весь оставшийся пайплайн
5. Паттерны permission errors — core/followup.py:PERMISSION_PATTERNS
permission denied, ручное применение, cannot write, read-only, manually appl, ...
6. Post-pipeline hooks — core/hooks.py
События: pipeline_completed, task_auto_approved, task_permission_retry
Пробелы — что НЕ реализовано
Gap 1: Auto-followup не вызывается из run_pipeline
generate_followups() существует в core/followup.py, но нигде не вызывается автоматически. В run_pipeline после завершения пайплайна — только хуки.
Gap 2: Auto-resolution pending_actions в auto mode
generate_followups() возвращает pending_actions (permission-blocked followup items) с опциями ["rerun", "manual_task", "skip"]. В auto mode нет логики автоматического выбора опции.
Gap 3: Наследование режима followup-задачами
Задачи, созданные через generate_followups(), создаются с execution_mode=None (наследуют от проекта). Это правильное поведение, но не задокументировано.
Решения
D1: Где хранить режим
Решение: двухуровневая иерархия (уже реализована, зафиксируем).
| Уровень | Поле | Дефолт | Переопределяет |
|---|---|---|---|
| Глобальный | — | review |
— |
| Проект | projects.execution_mode |
'review' |
глобальный |
| Задача | tasks.execution_mode |
NULL |
проект |
Глобального конфига нет — осознанное решение. Каждый проект управляет своим режимом. Задача может переопределить проект (например, форсировать review для security-sensitive задач).
Изменения БД не нужны — структура готова.
D2: Как runner обходит ожидание approve в auto mode
Решение: уже реализовано. Зафиксируем контракт:
run_pipeline() в auto mode:
1. Все шаги выполняются последовательно
2. При успехе → task.status = "done" (минуя "review")
3. Хук task_auto_approved + pipeline_completed
4. generate_followups() автоматически (Gap 1, см. D4)
В review mode — без изменений: task.status = "review", generate_followups() не вызывается автоматически.
D3: Auto-rerun при permission issues — лимит и критерии
Что считать permission issue:
Паттерны из PERMISSION_PATTERNS в core/followup.py. Список достаточен, расширяется при необходимости через PR.
Лимит попыток: 1 retry per step (уже реализовано). Обоснование:
- Permission issue — либо системная проблема (нет прав на директорию), либо claude CLI требует
--dangerously-skip-permissions - Второй retry с теми же параметрами не имеет смысла — проблема детерминированная
- Если 1 retry не помог →
task.status = "blocked"даже в auto mode
Поведение после retry:
allow_write=True применяется ко всем последующим шагам пайплайна (не только retry шагу). Это безопасно в контексте Kin — агенты работают в изолированном рабочем каталоге проекта.
Хук task_permission_retry:
Срабатывает перед retry — позволяет логировать / оповещать, но не блокирует.
Итоговая таблица поведения при failure:
| Режим | Тип ошибки | Поведение |
|---|---|---|
| auto | permission error (первый) | retry с allow_write=True |
| auto | permission error (после retry) | blocked |
| auto | любая другая ошибка | blocked |
| review | любая ошибка | blocked |
D4: Auto-followup интеграция с post-pipeline hooks
Решение: generate_followups() вызывается из run_pipeline() в auto mode после task_auto_approved хука.
Порядок событий в auto mode:
1. pipeline успешно завершён
2. task.status = "done"
3. хук: task_auto_approved ← пользовательские хуки (rebuild-frontend и т.д.)
4. generate_followups() ← анализируем output, создаём followup задачи
5. хук: pipeline_completed ← финальное уведомление
В review mode:
1. pipeline успешно завершён
2. task.status = "review"
3. хук: pipeline_completed
← generate_followups() НЕ вызывается (ждём manual approve)
Почему после task_auto_approved, а не до:
Хуки типа rebuild-frontend (KIN-010) изменяют состояние файловой системы. Followup-агент должен видеть актуальное состояние проекта после всех хуков.
D5: Auto-resolution pending_actions в auto mode
generate_followups() может вернуть pending_actions — элементы, заблокированные из-за permission issues. В auto mode нужна автоматическая стратегия.
Решение: в auto mode pending_actions резолвятся как "rerun".
Обоснование:
- Auto mode = полный автопилот, пользователь не должен принимать решения
- "rerun" — наиболее агрессивная и полезная стратегия: повторяем шаг с
allow_write=True - Если rerun снова даёт permission error → создаётся manual_task (escalation)
auto mode + pending_action:
→ resolve_pending_action(choice="rerun")
→ если rerun провалился → create manual_task с тегом "auto_escalated"
→ всё логируется
review mode + pending_action:
→ возвращается пользователю через API для ручного выбора
D6: Наследование режима followup-задачами
Задачи, созданные через generate_followups(), создаются с execution_mode=None.
Решение: followup-задачи наследуют режим через проект (существующая иерархия D1).
Явно устанавливать execution_mode в followup-задачах не нужно — если проект в auto, все его задачи по умолчанию в auto.
Исключение: если оригинальная задача была в review (ручной override), followup-задачи НЕ наследуют это — они создаются "чисто" от проекта. Это намеренное поведение: override в задаче — разовое действие.
Итоговая карта изменений (что нужно реализовать)
| # | Файл | Изменение | Gap |
|---|---|---|---|
| 1 | agents/runner.py |
Вызов generate_followups() в auto mode после task_auto_approved |
D4 |
| 2 | core/followup.py |
Auto-resolution pending_actions в generate_followups() при auto mode |
D5 |
| 3 | web/api.py |
Endpoint для смены execution_mode проекта/задачи |
— |
| 4 | web/frontend |
UI переключатель Auto/Review (project settings + task detail) | — |
Что НЕ нужно менять:
core/db.py— схема готоваcore/models.py—get_effective_mode()готовcore/hooks.py— события готовы- Permission detection в
runner.py— готово
Риски и ограничения
-
Стоимость в auto mode:
generate_followups()добавляет один запуск агента после каждого пайплайна. При высокой нагрузке это существенный overhead. Митигация:generate_followups()можно сделать опциональным (флагauto_followupв project settings). -
Permission retry scope:
allow_write=Trueпосле первого retry применяется ко всем последующим шагам. Это агрессивно, но допустимо, т.к. агент уже начал писать файлы. -
Infinite loop в auto-followup: если followup создаёт задачи, а те создают ещё followup — нет механизма остановки. Митигация:
parent_task_idпозволяет отслеживать глубину. Задачи сsource: followup:*глубже 1 уровня — не генерируют followup автоматически. -
Race condition: если два пайплайна запускаются для одной задачи одновременно — БД-уровень не блокирует. SQLite WAL +
task.status = 'in_progress'в начале пайплайна дают частичную защиту, но не полную.
Статус реализации
- DB schema:
execution_modeвprojectsиtasks get_effective_mode()с приоритетом task > project > review- Auto-approve:
task.status = "done"в auto mode - Permission retry: 1 попытка с
allow_write=True - Хуки:
task_auto_approved,pipeline_completed,task_permission_retry - Auto-followup: вызов
generate_followups()изrun_pipeline()в auto mode (Gap 1) - Auto-resolution
pending_actionsв auto mode (Gap 2) - API endpoints для управления
execution_mode - Frontend UI для Auto/Review переключателя