Skip to content
Deep Work Plan сегодня на Product Hunt Поддержать
← Все документы спецификации

Состояние плана

Версия 5.0.0. Статус: стабильная. Этот документ специфицирует машиночитаемый слой состояния плана методологии Deep Work Plan, теперь приведённый в соответствие с собственной версией стандарта DWP — перенумерация не ослабляет ни одно существующее требование. Эта редакция также документирует защищённый обновитель состояния, верифицированную публикацию плана и правила истинности доказательств, которым должен удовлетворять завершённый план (см. ниже). Ключевые слова MUST, MUST NOT, SHOULD, SHOULD NOT и MAY следует трактовать так, как описано в RFC 2119.

Два JSON-артефакта — manifest.json (статическая идентичность плана) и state.json (живое, пер-задачное состояние выполнения, включая результаты validation gates) — которые каждый план MAY нести рядом со своими markdown-файлами, и которые неавтономное выполнение (см. Протокол агента) и рабочие пространства агента без git (см. Архетипы §3) MUST нести.

Markdown-план остаётся человекочитаемым источником истины. Слой JSON — это производная проекция: он регенерируется агентом в определённых протокольных точках, никогда не редактируется вручную и ни в коем случае не должен молча расходиться с markdown. Его цель — интероперабельность: линтинг, проверка соответствия, diffing, дашборды, обнаружение в реестре и синхронизация с внешней инфраструктурой сессий — ни одно из этих применений нельзя строить надёжно на прозе.

Зачем это нужно

До версии v1.1 планы существовали только как прозаический markdown. Это сохраняло их проверяемость и агент-нейтральность, но не оставляло ничего, что инструмент мог бы валидировать, сравнивать или потреблять: никакого conformance gate, никакого обнаружения рассинхронизации между README.md и PROGRESS.md, никакого способа для демона или облачной сессии узнать состояние плана, не разбирая прозу. Версия v1.2 добавляет JSON-проекцию, не понижая markdown — проекция производится из markdown так же, как lockfile производится из манифеста.

Расположение

План, использующий слой состояния, имеет следующую структуру:

.dwp/plans/PLAN_{name}/
├── README.md            ← человеческий источник истины (без изменений)
├── PROGRESS.md          ← нарративный журнал (без изменений)
├── PROMPTS.md           ← без изменений
├── manifest.json        ← статическая идентичность (записывается при материализации)
├── state.json           ← живое состояние (перезаписывается в протокольных точках)
├── analysis_results/
└── {N}.task_{...}.md

manifest.json MUST быть записан ровно один раз — когда поток create материализует план — и MUST NOT изменяться впоследствии, за исключением миграции версии спецификации, зафиксированной в PROGRESS.md.

state.json MUST перезаписываться агентом в каждой из этих протокольных точек: материализация плана (все задачи pending), начало задачи (in_progress), каждый запуск validation gate (запись gate добавляется или обновляется), завершение задачи (completed, в составе протокола завершения задачи в Спецификации DWP), контрольная точка перед любым запланированным прерыванием и остановка blocked.

Оба файла MUST записываться атомарно: записать во временный файл в той же директории, затем переименовать поверх целевого. Аварийная запись MUST NOT оставлять усечённый JSON-файл на месте.

Когда слой обязателен

  • При интерактивном выполнении в git-репозитории слой состояния RECOMMENDED для новых планов и OPTIONAL для планов до версии v1.2. План без него остаётся conformant.
  • При автономном (unattended) выполнении слой состояния REQUIRED.
  • В рабочем пространстве агента без git слой состояния REQUIRED: state.json несёт информацию для восстановления, которую git log несёт в репозитории.

manifest.json — идентичность плана

{
  "schema": "https://deepworkplan.com/schema/plan-manifest/v2.json",
  "spec_version": "2.4.0",
  "name": "PLAN_payment_webhooks",
  "title": "Add payment webhook handling",
  "archetype": "individual",
  "rigor": "standard",
  "plan_format": "full",
  "created_at": "2026-06-09T14:00:00Z",
  "created_by": { "agent": "claude-code", "model": "claude-fable-5" },
  "tags": ["backend", "payments"],
  "task_count": 7,
  "parent_plan": null
}

schema, spec_version, name, archetype, rigor, created_at, task_count и plan_format REQUIRED.

archetype MUST быть одним из: individual, orchestrator-hub, agent-workspace.

rigor MUST быть одним из: micro, standard, deep (см. Пропорциональная строгость).

plan_format MUST быть одним из: lite, full — представление, выбранное при создании (см. Lite-планы). Оно неизменяемо на уровне манифеста: последующее повышение с Lite до Full фиксируется в state.json, а не путём переписывания манифеста.

parent_plan связывает дочерний план с планом-оркестратором ({repo}:{plan_name} или null).

created_by SHOULD идентифицировать создавшего агента и модель. Он MUST NOT содержать секреты, токены или идентификаторы пользователей помимо отображаемого имени.

state.json — живое состояние выполнения

{
  "schema": "https://deepworkplan.com/schema/plan-state/v2.json",
  "plan": "PLAN_payment_webhooks",
  "updated_at": "2026-06-09T16:42:10Z",
  "updated_by": { "agent": "claude-code", "model": "claude-fable-5" },
  "status": "in_progress",
  "completed_count": 2,
  "task_count": 7,
  "format": "full",
  "materialization": "ready",
  "approval": "approved",
  "promotion": null,
  "tasks": [
    {
      "id": 1,
      "locator": { "kind": "file", "value": "1.task_webhook_endpoint.md" },
      "title": "Create webhook endpoint",
      "status": "completed",
      "started_at": "2026-06-09T14:10:00Z",
      "completed_at": "2026-06-09T15:02:33Z",
      "commit": "a1b2c3d",
      "gates": [
        {
          "command": "pnpm run test",
          "passes": true,
          "exit_code": 0,
          "last_run": "2026-06-09T15:01:50Z",
          "evidence": "42 passed, 0 failed"
        }
      ],
      "outcome": {
        "tried": ["raw body parsing via middleware"],
        "failed": ["initial signature check used wrong header"],
        "worked": "verify signature against X-Sig header before JSON parse",
        "notes": "stripe-style HMAC; see analysis_results/webhook_notes.md"
      }
    },
    {
      "id": 3,
      "locator": { "kind": "file", "value": "3.task_retry_queue.md" },
      "title": "Add retry queue",
      "status": "in_progress",
      "started_at": "2026-06-09T16:30:00Z",
      "gates": []
    }
  ],
  "checkpoint": {
    "task": 3,
    "step": "instructions:4",
    "at": "2026-06-09T16:42:10Z",
    "note": "queue table migrated; worker loop not yet wired"
  },
  "blocked": null
}

Записи задач в Lite-плане используют локатор inline, указывающий на якорь задачи в README.md, вместо отдельного файла — всё остальное в записи (gates, outcome, status) работает так же:

{
  "format": "lite",
  "materialization": "ready",
  "approval": "pre_approved",
  "promotion": null,
  "tasks": [
    {
      "id": 2,
      "locator": { "kind": "inline", "value": "#task-2" },
      "title": "Add retry queue",
      "status": "pending",
      "gates": []
    }
  ]
}

Формат, материализация, одобрение и повышение

format MUST быть одним из: lite, full и зеркально отражает plan_format манифеста — здесь оно изменяемо, в отличие от манифеста, потому что Lite-план MAY впоследствии быть повышен до Full. materialization MUST быть одним из: materializing (папка плана записывается), ready (материализация завершена) или promoting (повышение с Lite до Full выполняется). approval MUST быть одним из: pending, approved, pre_approved; оно OPTIONAL в этой схеме, чтобы план, записанный до того, как это поле стало фиксироваться, всё равно проходил валидацию — когда оно отсутствует, значением считается строка Approval в README, а при отсутствии обоих — pending. promotion равно null вне повышения, либо это объект, фиксирующий намерение повышения и целевые задачи, пока materialization имеет значение promoting. См. Lite-планы — полный жизненный цикл, который кодируют эти поля.

Записи задач

Каждая задача — отдельный файл в Full-плане либо инлайн-запись {#task-N} в Lite-плане — MUST иметь ровно одну запись в tasks, с ключом по своему номеру (id) и своему locator. locator.kind MUST быть file (Full — value это имя файла задачи) либо inline (Lite — value это якорь задачи, #task-N).

status MUST быть одним из: pending, in_progress, completed, blocked, skipped. skipped допустим только когда пользователь явно исключил задачу из области через refine; state.json MUST NOT использоваться для молчаливого пропуска работы.

Запись completed MUST содержать completed_at и, где план делает коммиты, короткий хеш коммита (commit) — это ссылка трассируемости между планом и кодом.

Записи gate

Каждый запуск команды валидации SHOULD записываться как gate-запись: command, passes (булево), exit_code, last_run и краткая человекочитаемая строка evidence (итоговая строка или путь в собственном для плана analysis_results/ (внутри собственной папки плана, никогда в корне репозитория), но никогда не полный вывод команды).

Задача MUST NOT помечаться как completed в state.json, пока любая из её gate-записей имеет passes: false без последующего успешного запуска. Gate-записи — это машинный эквивалент принципа «никогда не помечать завершённым без доказательств» — шаблон флага passes для каждого элемента, защищающий от преждевременного завершения.

Записи outcome как эпизодическая память

Завершённая задача SHOULD нести запись outcome: что было tried, что failed, что worked и свободные notes. Каждая запись должна умещаться в одну строку.

Записи outcome превращают завершённый план в доступную эпизодическую память: агент (или платформа для индексации памяти) впоследствии сможет вспомнить, как была решена конкретная проблема, а не только то, что она была решена. Они питают задачно-локальные решения по skills и сверку решений по skills в Final Review, которая читает их при поиске паттернов. На таких платформах, как Hermes, индексирующих память агентов, записи outcome в state.json делают завершённые планы напрямую доступными через будущие сессии.

Контрольная точка и заблокированное состояние

checkpoint фиксирует наиболее детальную точку возобновления внутри текущей задачи: id задачи, свободный локатор step, метку времени и однострочную заметку. Агент SHOULD обновлять его при каждой паузе внутри задачи; он MUST обновлять его перед любым запланированным прерыванием в автономном режиме.

blocked равен null или { "task": N, "reason": "...", "since": "...", "needs": "..." }. Автономный агент, столкнувшийся с условием остановки, MUST заполнить поле blocked перед остановкой — именно так следующее «сердцебиение» демона или человек узнает, почему план остановился.

Проекция и согласование

Markdown MUST выигрывать каждое разногласие. Если state.json говорит, что задача 4 completed, но план README показывает непомеченный чекбокс, — файл состояния устарел.

Возобновляющий агент MUST сравнить список чекбоксов в README с state.json перед продолжением. При рассинхронизации он MUST регенерировать state.json из markdown (и git log, где он доступен), зафиксировать согласование в PROGRESS.md и только после этого продолжать.

Под-навык verify MUST рассматривать рассинхронизацию как conformance-находку: сообщить, какие задачи расходятся и в каком направлении.

Инструменты, отличные от исполняющего агента, MUST рассматривать оба JSON-файла как доступные только для чтения.

Защищённые обновления состояния

Обычные записи прогресса проходят через поставляемый вместе с методологией точечный обновитель, а не через перезапись всего файла. Он безоговорочно отклоняет некорректное состояние и отказывается помечать задачу completed без прикреплённого непустого доказательства gate — для команды, чей собственный вывод содержит символы канала (pipe), доступна форма --gate-json, и обновитель принимает тот же закрытый объект gate, описанный выше. Повторные попытки заменяют только собственную запись своей команды; другая команда сохраняет собственную отдельную запись. --block-reason фиксирует блокер; --resolve-blocker разрешает блокер только текущей задачи, никогда — блокер другой задачи. Пропущенная работа никогда не может сделать план completed. --reopen-reason фиксирует намерение вызывающего изменить план через refine — изменение и любое доказательство, которое оно делает недействительным, MUST быть сначала зафиксировано в журнале задачи. --expected-sha256 отклоняет запись против снимка состояния, который с тех пор изменился. Кооперативная директория .lock сериализует конкурирующих писателей; замок писателя, который аварийно завершился, MUST быть проверен перед удалением, и никакой защиты не заявляется против редактора, который полностью обходит замок. Эти записи утверждают результаты — они сами по себе не доказывают, что команда была выполнена или что её вывод был семантически принят.

Верифицированная публикация плана

Перед объявлением завершения журналы завершённых задач (каждый несёт свою диспозицию skills и, в Final Review, своё решение по документации), индекс README и PROGRESS.md MUST быть составлены из заработанного источника и результатов приёмки. Финальная задача плана затем закрывается через поставляемый финализатор: его терминальный переход валидирует завершённого кандидата по каждому артефакту плана перед записью состояния, впоследствии верифицирует файлы и фиксирует квитанцию analysis_results/FINALIZATION.json. Выдуманный проходящий gate MUST NOT подкреплять этот переход — квитанция является внешним доказательством того, что действительно было проверено, а не собственной предпосылкой самой себя. Далее запускается bash ../verify/conformance.sh --plan PLAN_name — против реальных артефактов на диске.

Прерванная публикация оставляет на месте маркер .finalizing.json; обычная верификация проваливается до тех пор, пока доказательство не будет изучено и вспомогательное средство восстановления не завершится успешно для того же кандидата — ничто не возобновляет публикацию по предположению. Устаревший кооперативный замок требует подтверждения, что ни один писатель более не активен, перед удалением. Ничто на этом уровне не коммитит, не пушит, не выполняет сохранённую команду gate и не восстанавливает markdown плана молча. Отсутствующий интерпретатор Python даёт UNVERIFIED, никогда не completed.

Истинность доказательств и поправки

Каждое изменение области, критериев приёмки или отсрочки задачи несёт одну неизменную запись поправки: исходный критерий дословно, что было замечено, диспозицию, причину, полномочие, стоящее за ней (пользователь, разработчик или доказательство), затронутые задачи и то, какое доказательство было признано недействительным, а какое сохранено. Поправки добавляются, но никогда не датируются задним числом; manifest.json сохраняет своё происхождение при создании и никогда не переписывается, чтобы соответствовать изменившейся живой области.

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

  • Завершённое расследование (Completed investigation) — реальная зафиксированная работа; она закрывает задачу только против пересмотренного критерия, который её называет, никогда — против исходного, как он был написан.
  • Невыполненный сценарий (Unexecuted scenario) — зафиксирован как не выполненный; он не даёт проходящего доказательства ни в какую эпоху.
  • Отложенное требование (Deferred requirement) — критерий перемещается в именованную целевую задачу с зафиксированным полномочием; только эта поправка закрывает источник.
  • Провалившийся gate (Failed gate) — остаётся проваленным до тех пор, пока то же самое намерение приёмки не будет перезапущено и не пройдёт; повторная попытка заменяет только собственную команду.
  • Достигнутый продуктовый результат (Achieved product outcome) — критерий как он написан, верифицированный собственным gate; единственное состояние, которое завершает задачу без изменений.

Обеспечение соблюдения механическое везде, где это позволяют записи. Доказательство gate, помеченное «признано недействительным через refine», остаётся сохранённой историей, но никогда не проходящим доказательством, и завершённая задача, всё ещё опирающаяся на него, сообщается проверяющим. Проходящая запись, чей собственный текст признаёт, что проверка никогда не выполнялась (например, «никогда не запускалась», «не выполнялась» или «не может быть измерено»), является противоречием и сообщается таким же образом — как и завершённая задача, чей собственный журнал всё ещё гласит Status: pending. Нарративные противоречия за пределами этих — отчёт, чьи выводы расходятся с его собственным чек-листом, — требуют человека-рецензента; проверяющий сообщает о том, что говорят записи, а не о том, что значит проза. Пользователь MAY явно принять ограниченное исключение с зафиксированным полномочием; неприсутствующее заранее данное согласие никогда не является общим разрешением отказаться от ключевой цели, а недостижимый обязательный критерий — это блокер, а не завершённая работа.

Версионирование схем

Обе схемы версионируются через URL. Аддитивные поля допустимы в рамках версии; переименование или изменение типа поля требует новой версии схемы и примечания о миграции в журнале изменений спецификации. Эта ревизия вводит /v2.json для обеих схем: поле file записи задачи становится типизированным locator ({"kind": "file" | "inline", "value": ...}), манифест получает plan_format, а файл состояния получает format, materialization, approval и promotion — вместе поля, необходимые Lite-планам (см. Lite-планы). Манифесты и файлы состояния /v1.json остаются валидными и никогда не переписываются в v2 молча; сессия refine MAY осознанно мигрировать один из них. Поле spec_version в манифесте фиксирует версию спецификации DWP, под которой был создан план; агент, встречающий план новее своей установленной спецификации, SHOULD сообщить об этом, а не угадывать.