claude-harness/docs/HARNESS.md

17 KiB
Raw Blame History

Как работает обвязка

Идея

Каждый инструмент отвечает за один вид памяти, и слои не пересекаются:

  • Gitea помнит что делать между сессиями и неделями. Issue = фича, PR = точка человеческого контроля.
  • OpenSpec помнит как система должна себя вести. openspec/specs/ — текущее состояние, openspec/changes/<id>/ — дельта текущей фичи. После merge дельта архивируется и вливается в specs.
  • Superpowers ведёт процесс внутри одной фичи: brainstorming → writing-plans → subagent-driven-development → ревью → finishing-a-development-branch. Прогресс внутри плана живёт в ledger (.superpowers/sdd/<plan>/progress.md), который переживает компакцию и обрыв сессии, но удаляется после завершения.
  • codegraph — карта кода для сабагентов: codegraph_explore вместо grep/Read по файлам. MCP-сервер привязан к папке запуска сессии (основной checkout); индекс worktree строится отдельно (codegraph init в worktree) и опрашивается через параметр projectPath.
  • Хуки — то, что нельзя доверять промпту. Superpowers просит, хуки запрещают.

Клей между слоями — global/CLAUDE.md. Superpowers сам заявляет, что инструкции пользователя выше skills, поэтому вся маршрутизация живёт там.

Цикл фичи

# Шаг Кто Артефакт
1 Формулируете цель одной фразой; агент заводит issue вы + агент issue #N
2 brainstorming: классификация spike / bounded / architectural, вопросы по одному, подходы, дизайн по частям агент + вы —
3 Спека в openspec/changes/<id>/ (proposal, specs/*, design) + раздел «Decisions made without discussion»; ваше утверждение агент, вы change
4 using-git-worktrees: ветка feat/N-slug агент worktree
5 writing-plans: план с Global Constraints, Review Focus, полным кодом задач; Task 1 — тестовая инфраструктура; ваше утверждение агент, вы docs/superpowers/plans/*.md
6 SDD: контроллер (sonnet) → implementer на задачу (haiku/sonnet) → reviewer (sonnet) → fix loop до 5 раундов → ledger агент автономно коммиты, ledger
7 Финальное ревью всей ветки (opus), одна волна фиксов агент —
8 finishing-a-development-branch: PR в Gitea с «Rulings I made» агент PR
9 Ревью PR в Gitea; комментарии → receiving-code-review → правки в ветке; вы делаете merge вы ↔ агент merge
10 «Закрывай»: чеклист из 7 пунктов (см. CLAUDE.md) агент archive, closed issue, follow-up issue, чистый main

Шаги 6–8 идут без остановок. Агент останавливается только на необратимой операции, вопросе безопасности, побочном эффекте вне worktree или плане, который невозможно исполнить.

Bounded-задача (флаг, фикс) идёт короче: дизайн в чате, файл .bounded в корне worktree (пропускает хук require-plan), TDD, коммит, PR. Без OpenSpec change и без плана.

Subagent-driven development

Три роли, один цикл на задачу:

  • Контроллер видит план, спеку, ledger и короткие статусы. Режет план на брифы (task-brief), запускает сабагентов, выносит рулинги, ведёт ledger. Кода не пишет. Запускается фоновым сабагентом на sonnet.
  • Implementer — свежий сабагент на задачу. Видит только свой бриф и интерфейсы соседних задач. TDD, коммит, отчёт в файл, статус DONE / DONE_WITH_CONCERNS / NEEDS_CONTEXT / BLOCKED.
  • Reviewer — свежий сабагент, получает бриф, отчёт и diff файлом (review-package). Два вердикта: соответствие спеке и качество.

Fix loop: раунды 1–3 продолжают того же implementer, 4–5 — свежий на более сильной модели. После пятого контроллер адьюдицирует сам и записывает рулинг. Minor-замечания в цикл не входят, откладываются до финального ревью.

Шаблоны сабагентов входят в superpowers: implementer-prompt.md, task-reviewer-prompt.md, re-review-prompt.md, code-reviewer.md. Это роли процесса, а не доменные специалисты; доменная экспертиза приходит через бриф с кодом, проектный CLAUDE.md и доменные skills.

Решения без обсуждения

Единственное место, где видно, что агент решил за вас. Правило в CLAUDE.md: любое такое решение — на этапе спеки, плана или исполнения — пишется в openspec/changes/<id>/design.md, раздел ## Decisions made without discussion, с датой, обоснованием и ценой ошибки. Ledger удаляется, чат теряется, design.md архивируется со спекой.

Читать: спеку один раз при утверждении, раздел решений каждый раз, когда он пополняется (после спеки, после плана, в финальном отчёте SDD). Каждое решение — вопрос «согласен ли я»: согласен — ничего не делать; не согласен — сказать агенту, он поправит; непонятно — спросить.

Маркировка находок

Всё, что всплывает за фичу — замечания ревьюеров, рулинги контроллера, наблюдения, комментарии в PR — получает маркер источника и сохраняет его во всех документах: ledger → отчёт контроллера → PR → design.md → follow-up issue.

Маркер Источник Пример
T<n>.<k> minor из ревью задачи n плана T1.1 — Node-глобалы проходят проверку типов в src/core
C-n / I-n / M-n финальное ревью ветки: critical / important / minor M-3 — жёсткий путь к vault в конфиге сборки
R-n рулинг контроллера (процесс, план vs спека, состав фикс-волны); рядом номер решения в design.md R-5 (design #33) — claimAll следует спеке, не плану
O-n наблюдение контроллера вне ревью O-1 — счётчики в отчётах implementer неточны
H-n комментарий человека в PR H-1 — переименовать поле

Статус каждой находки — fixed <commit>, deferred или rejected <причина>; пункт без статуса в финальном отчёте контроллера считается ошибкой. Отложенное живёт не в ledger (он удаляется) и не в чате, а в одной issue Gitea Follow-ups from #N, которую агент заводит при закрытии. Следующая фича начинается с tea issues ls — и там эти пункты видны.

Зачем так: на пилоте контроллер придумал маркеры сам (T по номеру задачи без счётчика, P/F для рулингов), два пункта остались без маркера, а весь список отложенного жил только в удалённом ledger и в чате.

Хуки

Правило Файл Механизм
Никаких изменений на main / master / detached HEAD guard-main.sh → harness_target.py, PreToolUse на Edit/Write/MultiEdit/Bash решает по цели записи, а не по cwd. Цели: файл Edit/Write; в Bash — редиректы (кроме /dev/null и N>&M), tee, rm, mv, cp, sed -i, npm install, openspec archive… с учётом cd и git -C; git-мутации (commit, add, merge, reset…; push — только если пушит в main; switch -c в той же команде меняет ветку). Цель вне репозитория или в worktree на ветке — пропуск; неразрешимый путь ($VAR) — пропуск; git-мутация с неопределённым репозиторием — блок. Исключений нет: архив OpenSpec — отдельным PR
Правки в коде только при плане или .bounded require-plan.sh → harness_target.py, PreToolUse на Edit/Write/MultiEdit по репозиторию правимого файла, а не по cwd: защищает любой src/ на любой глубине (api/src/, packages/*/src/) или каталоги из .claude/code-paths; ищет план в docs/superpowers/plans/ для ветки этого репозитория или файл .bounded в его корне
Обвязка подключена к проекту harness-check.sh, SessionStart при старте сессии проверяет openspec/, .codegraph/, секцию в CLAUDE.md; если чего-то нет — пишет агенту инструкцию запустить ~/.claude/harness/adopt-project.sh (спросив пользователя; HARNESS_AUTO_ADOPT=1 — без вопроса)
Подсказка роли по заголовку сессии role-hint.sh, SessionStart (все источники) читает session_title; если начинается с «dev, admin, analyst или qa» — одна строка-подсказка вызвать /role; ничего не блокирует
Тесты зелёные перед коммитом git pre-commit в проекте (не входит в пакет) обычный git-хук с командой тестов

Exit 2 блокирует вызов и показывает агенту stderr, поэтому агент сам делает то, что просит сообщение. Сообщение начинается с BLOCKED [guard-main]: или BLOCKED [require-plan]: и называет цель, репозиторий и выход. Оба обхода, замеченные на пилоте (запись через echo > вместо Write; push через detached HEAD), закрыты.

Регрессия хуков — корпус skills/harness-doctor/fixtures/hook-cases.jsonl: реальные команды из транскриптов пилота с ожидаемым вердиктом. По источникам — bash tests/run.sh hook, по установленным копиям — строка «корпус хуков» в doctor.sh. Корпус собирается из сырой выгрузки docs/retro/scripts/hook_cases_build.py; разметка — в этом скрипте. Разбор одной команды: python3 ~/.claude/hooks/harness_target.py targets '<команда>' <cwd>.

Дисциплина между сессиями

Новая сессия начинается с роли (/role), затем tea issues ls и openspec list, а не с памяти о прошлой. Незавершённый план возобновляется из ledger в worktree. Связка разваливается не на исполнении, а на закрытии — поэтому «закрывай» выполняет весь чеклист без остановок.

Роли

Одна сессия — одна роль: dev, admin, analyst, qa. Роль даёт сессии только свои правила, свои файлы на старте и свой раздел памяти; процесс разработки (superpowers → Gitea → OpenSpec, SDD, чеклист закрытия) живёт в роли dev и не загружается в сессии admin.

Два слоя, оба в git: общий — ~/.claude/roles/<r>.md (из пакета, install.sh), проектный — <workspace>/.claude/roles/<r>.md (для dev — файл, для остальных — симлинк в репозиторий направления admin/, qa/, analysis/). Формат одинаковый: четыре раздела «Процесс», «Читать на старте», «Не делать», «Делегировать»; при конфликте побеждает проектный слой.

Выбор роли, от автоматического к ручному: заголовок сессии (claude -n "admin …"; хук role-hint.sh печатает подсказку [claude-harness] Роль сессии: admin), вывод из первого сообщения (правило в глобальном CLAUDE.md: объявить «Роль: admin; если не так, скажи»), явно — /role <r>. Skill /role читает оба слоя, раздел памяти роли, строки «Читать на старте», а строки с префиксом brief: отдаёт фоновому агенту briefing, который возвращает выжимку: активные задачи, решения, открытые вопросы, ловушки.

Workspace из нескольких репозиториев (не git, cwd всех сессий) описывается таблицей | Каталог | Репозиторий | Роль | в его CLAUDE.md; link-roles.sh по ней создаёт симлинки на проектные файлы ролей и агентов направлений. Память агентов (memory: project) через симлинк каталога не работает (проверено 2026-10-11, спека, раздел 11), поэтому агентам направлений применяется запасной вариант спеки 6.5: поле memory не используется, промпт агента велит читать <dir>/notes/agent-memory.md при старте и дописывать в конце. adopt-project.sh --workspace и new-project.sh --workspace --role … собирают workspace из шаблонов; doctor.sh проверяет ссылки и размеры.

Политика памяти (глобальный CLAUDE.md): состояние задачи — в трекере; уроки, решения владельца и рецепты — в notes/ направления и памяти агентов (в git); в локальной auto-memory — только ловушки машины и индекс со ссылками. При закрытии файл auto-memory задачи сворачивается в строку registry-closed.md.

Стоимость

Bootstrap superpowers (~3 КБ) вставляется на каждом старте и после компакции. SDD стоит свежий контекст на задачу и на ревью; подробный план с готовым кодом позволяет отдать большинство задач haiku. Для планов до 5 задач дешевле executing-plans (Native): один контекст, одно ревью в конце.