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 (живий стан виконання по завданнях, включно з результатами валідаційних gate) — що будь-який план MAY нести поряд зі своїми markdown-файлами, а автономне виконання (див. Протокол агента) та робочі простори без git (див. Архетипи §3) MUST нести.

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

Навіщо це потрібно

До v1.1 плани були виключно у форматі prose markdown. Це зберігало їхню придатність до аудиту й агентонезалежність, але не лишало нічого, що інструмент міг би валідувати, порівнювати чи споживати: жодного 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), кожен запуск валідаційного gate (запис gate додається або оновлюється) та завершення завдання (completed, як частина протоколу завершення завдання в Специфікації DWP), контрольна точка перед будь-яким запланованим перериванням і зупинка blocked.

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

Умови застосування рівня

  • При інтерактивному виконанні в git-репозиторії рівень стану RECOMMENDED для нових планів і OPTIONAL для планів до v1.2. План без нього залишається відповідним.
  • При автономному виконанні рівень стану REQUIRED.
  • У робочому просторі агента без git рівень стану REQUIRED: state.json несе інформацію для відновлення, яку несе журнал git у репозиторії.

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 є дійсним лише тоді, коли користувач явно вилучив завдання зі scope через refine; state.json MUST NOT використовуватися для мовчазного пропускання роботи.

Запис completed MUST містити completed_at і, де план комітить, короткий хеш commit — це посилання на трасування від плану до коду.

Записи gate

Кожен запуск команди валідації SHOULD бути зафіксований як запис gate: command, passes (boolean), exit_code, last_run та короткий людиночитаний рядок evidence (підсумковий рядок або шлях під локальним для плану analysis_results/ (усередині власної теки плану, ніколи в корені репозиторія), ніколи повний вивід команди).

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

Записи результатів як епізодична памʼять

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

Записи результатів перетворюють завершений план на відновлювану епізодичну памʼять: агент (або платформа індексування памʼяті) може пізніше згадати, як було вирішено проблему, а не лише те, що вона була вирішена. Вони живлять диспозиції skills у межах завдань та узгодження skills у Final Review, яке читає їх під час виявлення патернів. На платформах, таких як Hermes, що індексують памʼять агента, записи результатів у state.json роблять завершені плани безпосередньо відновлюваними в майбутніх сесіях.

Checkpoint та заблокований стан

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

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

Проєкція та узгодження

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

Агент, що відновлює роботу, MUST порівняти список прапорців README із state.json перед продовженням. У разі десинхронізації він MUST перегенерувати state.json із markdown (та журналу git, де він доступний), зафіксувати узгодження в PROGRESS.md і лише тоді продовжити.

Суб-скіл verify MUST розглядати десинхронізацію як знахідку відповідності: повідомляти, які завдання розходяться і в якому напрямку.

Інструменти, відмінні від виконавчого агента, MUST ставитися до обох JSON-файлів як до файлів лише для читання.

Захищені оновлення стану

Звичайні записи прогресу проходять через постачений, цілеспрямований оновлювач, а не через повний перезапис файлу. Він одразу відхиляє неправильно сформований стан і відмовляється позначати завдання completed без прикріпленого непорожнього доказу gate — форма --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.

Істинність доказів і зміни

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

Пʼять станів доказів описують, проти чого може закритися запис завдання:

  • Завершене дослідження — реальна зафіксована робота; воно закриває завдання лише проти переглянутого критерію, що його називає, ніколи проти оригіналу як записано.
  • Невиконаний сценарій — зафіксований як не виконаний; він не додає жодного успішного доказу в жодну епоху.
  • Відкладена вимога — критерій переміщується до названого цільового завдання із зафіксованим повноваженням; лише ця зміна закриває джерело.
  • Провалений gate — залишається провальним, доки той самий намір приймання не буде повторно запущений і не пройде; повторна спроба перекриває лише власну команду.
  • Досягнутий продуктовий результат — критерій як записано, перевірений власним 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 повідомити про це, а не здогадуватися.