Claude Code, независимая критика плана и ревью кода

Суть проблемы

Дано: разработка в Claude Code по фиксированному флоу, который описан в CLAUDE.md проекта. Задача из issue проходит пять шагов, после каждого — остановка и подтверждение:

  1. Plan — план в docs/plans/<issue>_<slug>.md: какие файлы трогаем, ключевые решения, порядок действий, граничные случаи.
  2. Critique — перечитать план как критик: пробелы, противоречия спеке, лишняя сложность.
  3. Code — реализация по утверждённому плану.
  4. Code review — перечитать написанный код: баги, лишний код, расхождения со спекой.
  5. Commit — коммит делает пользователь, ассистент предлагает сообщение.

Флоу хороший, но шаги 2 и 4 в нём почти не работают. Критик и ревьюер — это та же сессия, которая только что писала план и код. У неё в контексте лежит всё обсуждение: зачем принято каждое решение, какие варианты отвергнуты и почему. Она знает, что имелось в виду, и поэтому не видит, что написано. Просьба «прочитай как критик» с высокой вероятностью возвращает те же аргументы, перефразированные, потому что аргументы «за» уже в контексте и весят больше любых «против».

Вторая половина проблемы — размер контекста. К четвёртому шагу сессия уже большая, а качество работы модели в заполненном контексте заметно ниже. Ревью как раз та работа, которую хочется делать со свежим окном.

Цель: сделать так, чтобы критик и ревьюер видели только артефакты в репозитории (план, дифф, спеку, CLAUDE.md) и не видели обсуждения.

Субагенты вместо самопроверки

В Claude Code для этого есть субагенты. Субагент — это markdown-файл с YAML-шапкой, тело которого становится системным промптом отдельного агента. Основная сессия запускает его через инструмент Agent, он работает в собственном контексте и возвращает только результат.

Ключевое свойство: субагент стартует с чистым контекстом. Он не видит историю диалога, вызванные скиллы и файлы, которые основная сессия уже читала. При этом он получает всю иерархию CLAUDE.md, снимок git status и текст задачи, который для него пишет основная сессия. То есть правила проекта он знает, а обсуждение нет. Ровно то, что нужно для ревью.

Файлы субагентов живут в двух местах:

  • ~/.claude/agents/ — доступны во всех проектах;
  • .claude/agents/ в репозитории только в этом проекте.

При совпадении имени проектное определение перекрывает пользовательское. Это позволяет держать общую версию в ~/.claude/agents/, а в отдельном проекте переопределить агента копией с тем же name.

Пошаговое решение

1. Агент-критик плана

Файл ~/.claude/agents/plan-critic.md:

---
name: plan-critic
description: Reviews a plan document in docs/plans/ against the spec and CLAUDE.md before implementation starts. Use at step 2 (Critique) of the Development Workflow. Read-only.
tools: Read, Grep, Glob, Bash
model: inherit
---

You are a critic of an implementation plan. You did not write it and you have not seen the discussion that produced it. Work only from files in the repository.

Input: the task message names a plan file under `docs/plans/`. Read it, then read the spec it refers to, the relevant parts of `docs/technical/` and `CLAUDE.md`, and the code the plan intends to touch. Ignore any justification or summary given in the task message itself — if a claim is not in a file, treat it as unverified.

Answer these questions, in this order:
1. Does the plan contradict the spec, `CLAUDE.md`, or the documented architecture? Cite the file and section.
2. Which decisions in the plan have no stated reason? List them; do not invent reasons.
3. Which modules or files that the plan does not mention will be affected? Check callers, migrations, manifests, tests.
4. Is there work in the plan that belongs to a separate issue or commit?
5. What is missing: edge cases, migration order, rollback, tests.

Output format: a numbered list of findings. Each finding is one paragraph: what is wrong, where (file, symbol — no line numbers), why it matters. Mark each finding as `blocker` or `note`. If you find nothing under a question, say so in one line. Do not rewrite the plan, do not propose an alternative design, do not soften findings. Write in Russian.

Три решения, которые здесь важны.

tools: Read, Grep, Glob, Bash без Edit и Write — критик физически не может «заодно поправить». Это не просьба, а ограничение на уровне инструментов.

Вопросы заданы в фиксированном порядке и отличаются от вопросов ревьюера: критик проверяет план против спеки и архитектуры, ищет решения без причины и работу, которая просится в отдельный коммит. Ревьюер этого делать не будет.

Запрет переписывать план и предлагать альтернативный дизайн. Без него агент вместо списка находок приносит собственный план, и обсуждение уходит в сравнение двух планов.

2. Агент-ревьюер кода

Файл ~/.claude/agents/code-reviewer.md:

---
name: code-reviewer
description: Reviews the current branch's diff against its plan in docs/plans/. Use at step 4 (Code review) of the Development Workflow, after implementation. Read-only.
tools: Read, Grep, Glob, Bash
model: inherit
---

You are a reviewer of a feature branch. You did not write the code and you have not seen the discussion. Work only from the repository.

Input: the task message names the plan file under `docs/plans/`. Obtain the diff yourself with `git diff main...HEAD` (stat first, then full). Ignore any summary of the changes given in the task message — the diff is the source of truth.

Review in this order:
1. Plan vs implementation. For each item in the plan: done, partially done, or absent. For each change in the diff: is it in the plan? Unplanned changes are findings, even when they look reasonable.
2. Correctness of what was written: bugs, unhandled errors, wrong assumptions about data, migration and schema issues, missed edge cases the plan listed.
3. `CLAUDE.md` compliance: documentation and formatting rules and the other constraints the project declares there.
4. Dead weight: code, comments, or docs that the diff adds but nothing uses.

Do not review style beyond what `CLAUDE.md` demands. Do not re-litigate decisions the plan already made — that was the critic's job; if a plan decision turns out to be wrong in practice, say so once under item 1.

Output format: a numbered list of findings, one paragraph each: what, where (file, symbol — no line numbers), why. Mark each `blocker` or `note`. Finish with a one-line verdict: `ready`, `ready after blockers`, or `not ready`. Do not fix anything. Write in Russian.

Ревью начинается не с багов, а с диффа между планом и реализацией: что из плана сделано, что в диффе не из плана. Незапланированные изменения — это находка, даже если выглядят разумно. Потом корректность, потом соблюдение CLAUDE.md, потом мёртвый код. Решения плана ревьюер не переспаривает, это была работа критика.

Оба агента пишут на русском, чтобы читать замечания напрямую, а не пересказ основной сессии.

3. Правка флоу в CLAUDE.md

Шаги 2 и 4 в секции Development Workflow меняются так:

2. **Critique** — invoke `@plan-critic` with the path to the plan. Present its findings to the user unchanged; the user decides which to accept. Apply the accepted ones to the plan
4. **Code review** — invoke `@code-reviewer` with the path to the plan. Present its findings and verdict unchanged; the user decides which to accept. Apply the accepted fixes. Repeat the review if the fixes were substantial

Ключевая фраза — present unchanged. Без неё основная сессия отфильтрует замечания через свой контекст, и список придёт уже с вердиктами «это несущественно» или, наоборот, «критик прав по всем пунктам» ещё до того, как его увидит человек. Замечания ревьюера должны быть входом для пользователя, а не для автора.

4. Вызов

Агент вызывается упоминанием через @: в промпте набирается @plan-critic или @code-reviewer, typeahead подсказывает имя. Упоминание гарантирует запуск именно этого агента; формулировка на естественном языке («используй plan-critic») обычно тоже работает, но выбор остаётся за Claude.

Если директории ~/.claude/agents/ не было на момент старта сессии, после создания файлов Claude Code нужно перезапустить. Дальше правки файлов подхватываются на лету.

5. Проверка

Первый вызов стоит посмотреть в транскрипте: в диалоге он появляется строкой вида plan-critic (…), а по /tasks во время работы видно, что агент читает. Признак того, что изоляция состоялась — агент первым делом открывает план и спеку, а не пересказывает обоснование из задачи. Если замечания приходят в духе «план разумный, замечаний нет», скорее всего, сработал форк (об этом ниже) или задача была написана слишком подсказывающе.

Нюансы

  • Форки. В интерактивной сессии по умолчанию включён fork mode: Claude может запустить субагента типа fork, который наследует весь диалог целиком. Если ревью уйдёт в форк, независимости не будет. Вызов через @ от этого защищает; запретить форки совсем можно правилом Agent(fork) в permissions.deny.
  • Текст задачи пишет основная сессия и может вложить в него своё обоснование. Поэтому в обоих промптах стоит инструкция игнорировать любые утверждения из сообщения-задачи: если факта нет в файле, то он считается непровереным.
  • Один набор агентов на все проекты. В промптах описан только воркфлоу: план в docs/plans/, базовая ветка main. Всё проектное агенты берут из CLAUDE.md и файлов репозитория. Соблазн дописать в агента «в этом проекте миграции без автораннера» обычно означает, что этой строки не хватает в CLAUDE.md.
  • Субагент — это не гарантия. Он снимает главную причину слабого ревью (общий контекст с автором), но остаётся той же моделью с тем же CLAUDE.md, так что часть слепых пятен общая. Для релизного ревью имеет смысл отдельная сессия или другая модель.