From 448f13ed4e88c4fc7f601915dd758d4e70458e7e Mon Sep 17 00:00:00 2001 From: Pavel Donin Date: Sun, 8 Nov 2026 12:59:39 +0100 Subject: [PATCH 1/7] Skip a typed epic key in /flow and run its acceptance in Finish --- .claude/skills/flow/SKILL.md | 51 +++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/.claude/skills/flow/SKILL.md b/.claude/skills/flow/SKILL.md index 69105e7..b6fcf83 100644 --- a/.claude/skills/flow/SKILL.md +++ b/.claude/skills/flow/SKILL.md @@ -37,7 +37,9 @@ own Step 0 with the same key; the subtasks of `P-N` pass it by the same rule. - The first argument is the run name ``, not a task key; at least one key follows. Otherwise print `usage: /flow […]` and stop. - Every key exists and is `new`, `planning`, `in_progress` (resume) or `review` - (already merged into this flow — skipped). Anything else → stop before starting. + (already merged into this flow — skipped; or the epic of «Subtasks»: a typed + key in `review` whose `$BIN/mp-task subtasks ` is not empty and that has no + `pr.md` naming this flow). Anything else → stop before starting. - `$BIN/mp-task project ` gives `checkoutPath`, `home` and `repository`; `checkoutPath` or `repository` `null` → say so and stop. - `$BIN/mp-task flow ` gives the project's `integration` and `prTarget`; @@ -54,6 +56,12 @@ its first occurrence stays. The status of each subtask decides by «Subtasks» o `$BIN/mp-task show ` in the question text. An included subtask gets `$BIN/mp-task status planning "в потоке : включена инженером"`. +A typed key in `review` that has subtasks and no `pr.md` naming this flow is the +epic: it is not scouted, planned, executed or recorded, and the run never +changes its status; the announced order and the skipped list of the flow score +name it ` — эпик, идут его подзадачи`. Its research may name an epic +acceptance («Finish», step 2). + ## Order Before any write, compute the order of the keys. The base is the run list @@ -97,7 +105,8 @@ time. Strictly one task at a time: the next key's `/do` starts only after the current key is recorded in the flow score. -1. Skip if already `review` with `pr.md` naming this flow. +1. Skip if already `review` with `pr.md` naming this flow, or if the key is the + epic («Subtasks»). 2. **Plan.** The `/plan ` procedure (Skill `plan`), unless the task folder already has `plan.md` and `derive.json` with no open threads. Its forks go to the engineer one at a time through `AskUserQuestion`, the recommendation first; no @@ -149,23 +158,41 @@ engineer answers so; the run then stops, later keys stay untouched. 1. In the flow worktree: the project's checks (by «Checks» of `docs/PIPELINE.md`; when the project's instructions name none, the check commands of the plans of all - keys, in order) once more on the assembled result (semantic conflicts between - tasks merge clean and only checks expose them). Red → a question with the + keys except the epic, in order) once more on the assembled result (semantic + conflicts between tasks merge clean and only checks expose them). Red → a question with the literal output; no PR until it is answered. -2. `gh pr create --repo --base --head flow/` — also for +2. **Epic acceptance**, only when a typed key is the epic («Subtasks») and its + research — `$($BIN/mp-task dir )/research.md` — has the line + `**Приёмка эпика:** да: `; no file, no such line or `нет` → no + epic acceptance. One acceptance of that criterion by + `docs/MANUAL-ACCEPTANCE.md` on the flow worktree's head, after step 1 and + before the PR, with the pitfalls of «Per key» step 5: the checklist is + written before the start, `acceptance.md` and the evidence go into the + epic's folder, the result is appended to the flow score; + `$BIN/mp-home-commit "flow : acceptance"`. The stands of + the subtasks («Per key» step 5) stay as they are. A failure inside a + subtask's plan goes to a new `task-executor` teammate in that subtask's + worktree (its own teammate was shut down at Record): the fix, one review + round, the checks, a new `--no-ff` merge into the flow worktree, step 1 + again, the failed items again. A failure that needs a decision or an + exceeded stand budget is a question. +3. `gh pr create --repo --base --head flow/` — also for one key — with title `Flow : , , …` and a body listing per key: title, plan URL, review verdict, checks, live acceptance (or «not required»), - the engineer's answers taken on the way; then the ending + the engineer's answers taken on the way; when a typed key is the epic, one line + with the epic acceptance result and the path of its `acceptance.md`, or «not + required»; then the ending `🤖 Generated with [Claude Code](https://claude.com/claude-code)`. -3. `gh pr checks --watch`. Red only on the test budget with `fail 0` → +4. `gh pr checks --watch`. Red only on the test budget with `fail 0` → report it to the engineer with the measurements, no rerun loop. Any other red → a question with the literal output. -4. For every key: `$BIN/mp-task status review "в потоке , ждёт ручной - проверки: "`. Append the PR URL to the flow score; +5. For every key except the epic: `$BIN/mp-task status review "в потоке + , ждёт ручной проверки: "`. Append the PR URL to the flow score; `$BIN/mp-home-commit "flow : PR"`. -5. Report: the PR URL, the keys in order with their review verdicts and acceptance, - open advice, the engineer's answers, the lead's edits of plans, and «ждёт вашей - ручной проверки; /ship flow/ мержит». +6. Report: the PR URL, the keys in order with their review verdicts and acceptance, + the epic acceptance result (when a typed key is the epic), open advice, the + engineer's answers, the lead's edits of plans, and «ждёт вашей ручной проверки; + /ship flow/ мержит». ## Never From d325920ca9d96e7fd3147cb573746b6af30ba091 Mon Sep 17 00:00:00 2001 From: Pavel Donin Date: Sun, 8 Nov 2026 12:59:45 +0100 Subject: [PATCH 2/7] Document the epic key and epic acceptance in the pipeline --- docs/PIPELINE.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md index 5ed97df..e3f56f2 100644 --- a/docs/PIPELINE.md +++ b/docs/PIPELINE.md @@ -139,7 +139,13 @@ subtask decides: - `blocked` or any other non-terminal status (`research`, `paused`, a custom one): one `AskUserQuestion` «include or skip». An included subtask gets `mp-task status planning "в потоке : включена инженером"` and goes on - as `planning`. + as `planning`; +- a typed key in `review` with subtasks and no `pr.md` of this flow is the epic: + not scouted, planned or executed, its status unchanged by the run, named in + the announced order and the flow score as «эпик — идут его подзадачи». When + its `research.md` has `**Приёмка эпика:** да: `, «Finish» of the + flow skill runs one acceptance of the epic on the flow branch before the PR, + `acceptance.md` in the epic's folder. The order: subtasks before their parent, then the «Связи» dependencies and shared files on top of it. While the flow runs a subtask that has a live tab of its own, @@ -286,8 +292,10 @@ place; `blocked` only when the engineer answers so. Cheap review advice inside the plan's scope is fixed by the executor, followed by one more review round; other advice goes into `pr.md` and the PR. The order of the tasks is announced with its reasoning before the start, not asked. A live -acceptance the plan names runs as part of the run, without a question; an -exceeded stand budget or a failure that needs a decision is a question. +acceptance the plan names runs as part of the run, without a question, +and so does the epic acceptance the epic's research names («Finish» of the flow +skill, before the PR); an exceeded stand budget or a failure that needs a +decision is a question. ## Checks From 78fbe83d072de66b85d5fdaae10bd6edbc9e1ceb Mon Sep 17 00:00:00 2001 From: Pavel Donin Date: Sun, 8 Nov 2026 13:11:18 +0100 Subject: [PATCH 3/7] Add the plan-challenger role --- .claude/agents/plan-challenger.md | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .claude/agents/plan-challenger.md diff --git a/.claude/agents/plan-challenger.md b/.claude/agents/plan-challenger.md new file mode 100644 index 0000000..5c2e993 --- /dev/null +++ b/.claude/agents/plan-challenger.md @@ -0,0 +1,35 @@ +--- +name: plan-challenger +description: Independent adversarial check of a research document that proposes a mechanism and implementation subtasks, against the engineer's verbatim request — what was not asked, what can be cut, what is reinvented, new weight, a shorter path. Read-only; returns its findings as one JSON object. +tools: Read, Grep, Glob, Bash +model: inherit +--- + +You are plan-challenger: an independent, adversarial check of a research document that proposes a mechanism and a list of implementation subtasks. You change nothing: no edits, no git writes, no fetch, no task changes, no derive calls. You get only the inputs below, never the author's plan or conclusions. + +Inputs: the engineer's verbatim request (source.md of the task), the research document, the clone and its expected SHA, the rules (docs/PIPELINE.md, AGENTS.md, the pipeline skills and roles). + +Check, in this order: +1. Freshness: the clone's origin/main equals the SHA the research names. Cheap fact checks: open at least ten repo: and home: citations and confirm each says what the research claims. +2. Against the verbatim request: what the research proposes that was not asked for. +3. Cut, merge, postpone: what can go without losing a stated goal of the request. +4. Reinvented: what already exists in the engine or the pipeline and is built again. +5. New weight: gates, rules, statuses, mandatory sections, commands or roles nobody asked for. +6. Shorter path: whether fewer subtasks, fewer files, or no new skill or role reach the same goals. +A finding that would change a gate or the approval rules is phrased as a choice for the engineer, not as a fix. + +Then try to refute each candidate finding yourself; drop every finding that does not survive. At most 12 findings, most valuable first. + +Each finding: type (not-requested | simpler | reinvented | new-gate | stale-base | fact | postpone), "now" (what the research says now), "proposal", "gain_loss" (what we gain / what we lose), "reasoning" (with file:line). Text fields in the engineer's language. + +Final message: exactly one JSON object {"main_sha_checked": "", "findings": [{"id", "type", "now", "proposal", "gain_loss", "reasoning"}]}. + +Bash is for reading only: git log, git show, git ls-remote, git rev-parse, grep, sed -n, cat, python3 that reads. Never a command that writes a file, the index, a ref, a remote, a task or a derive artifact. + +Your final message is your report, and it returns to the parent as the tool result. It is exactly one JSON object, nothing before or after it; no findings — an empty list, without invented ones: + +```json +{ "main_sha_checked": "", + "findings": [{ "id": 1, "type": "not-requested | simpler | reinvented | new-gate | stale-base | fact | postpone", + "now": "…", "proposal": "…", "gain_loss": "…", "reasoning": "… file:line" }] } +``` From 0ec01b257f2e121cfef07422292186faac1bfdba Mon Sep 17 00:00:00 2001 From: Pavel Donin Date: Sun, 8 Nov 2026 13:12:13 +0100 Subject: [PATCH 4/7] Add the /epic skill --- .claude/skills/epic/SKILL.md | 218 +++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 .claude/skills/epic/SKILL.md diff --git a/.claude/skills/epic/SKILL.md b/.claude/skills/epic/SKILL.md new file mode 100644 index 0000000..643a43a --- /dev/null +++ b/.claude/skills/epic/SKILL.md @@ -0,0 +1,218 @@ +--- +name: epic +description: Lead an epic of a registered project — a task whose research proposes a mechanism and its subtasks — through steps 1–5 in its chat: research by a task-executor teammate in the epic's folder, one task-reviewer round on version 1, publication to derive, independent check by plan-challenger, one question per finding with its decision row, version 2, the «Подзадачи» question and the subtasks created with --parent; the answer «Завести и запустить /flow» runs /flow . Triggered by "/epic ". +--- + +# /epic — an epic from research to its subtasks + +Read `docs/PIPELINE.md` in the engine root first: its section «Epics» holds the +table of steps with the commands of their signs, the required sections of the +research and the files of the epic's folder; «Approval semantics» says what typing +`/epic` and the answers authorize. Work inline in this chat: questions reach the +engineer only from here, subagents and teammates cannot ask. +`BIN=scripts/pipeline` (relative to the engine root, every session's working +directory). One key. + +## Step 0 — session scope + +`$BIN/mp-task scope`, then apply the «Session scope» rule of `docs/PIPELINE.md` to +`/epic `: `global` — any key; an organization (`org` is not `null`) — continue +only when the key has a code in `codes`; `P` — continue only when the key has the +code `P`; `P-N` — continue only when the key is `P-N` or its subtask by +`$BIN/mp-task subtasks P-N`; anything else (an argument that is not a key, a +malformed session key, a non-zero exit) — print the refusal text from +`docs/PIPELINE.md` and stop. No argument or more than one → print +`usage: /epic ` and stop. This step runs before «Input»: before +`$BIN/mp-task show`, before any derive call or subagent. + +## Input + +`$BIN/mp-task show `: + +- `new` or `planning` → «State»; +- `review` and `$BIN/mp-task subtasks ` is not empty → print + `: подзадачи заведены (<ключи>); следующий шаг, если поток ещё не запущен, — /flow , затем /ship flow/` + (`` is the output of `$BIN/mp-task slug `) and stop; +- any other status (`review` without subtasks included) → name the status and stop. + +`DIR=$($BIN/mp-task dir )`. + +## State + +Read the signs by the table of «Epics» of `docs/PIPELINE.md` with its commands +(`N`, `ROWS`, `V`, `mp-task subtasks`); the step is the first row from the top whose +sign holds. No row holds (for example `planning` without `research.md` — a plan of +`/plan`, not an epic) → print the signs found and stop. The run goes on from that +step through the next ones and stops only on questions and at the end of step 5. +Typing `/epic ` again after a break continues the same way; a teammate the step +needs that is not alive is spawned again with the same `name` (the key in lower +case) and the research-mode prompt of step 1. After every write into the epic's +folder: `$BIN/mp-home-commit ""` («Places» of `docs/PIPELINE.md`), +with the messages below. + +## Step 1 — research + +Rows «1, not started» and «1, under way». + +1. **Clone.** `$BIN/mp-task project ` gives `project`, `checkoutPath` and + `home`; when `checkoutPath` is `null`, say the project has no registered clone + and stop. `$BIN/mp-task flow ` gives `integration`; a non-zero exit → print + its error and stop. Update the base clone as step 3 «Per key» of + `.claude/skills/plan/SKILL.md`: `git -C fetch -q origin && + git -C merge -q --ff-only origin/` (only when it is + on `` and clean; otherwise read `origin/` and say so). + `SHA` is `git -C rev-parse origin/`. +2. **Reconnaissance**, only when there is no `research.md`. Spawn the `plan-scout` + subagent with: the full `source.md`, the project, the clone path and `SHA`, the + project's folder in home, `.yoke/` and `AGENTS.md` (else `CLAUDE.md`) of the + clone, the project's checks by «Checks» of `docs/PIPELINE.md`, and the brief: + «исследование эпика: факты с источниками (`repo:<путь>:<строки>` на `SHA`, + `home:<путь>`) о том, что запрос затрагивает сегодня, точки касания, которые + изменят подзадачи, и развилки с рекомендациями». Its forks are not asked of the + engineer: they go to the teammate as hypotheses the research weighs. «Not + solvable with what is given» → say what is missing and stop without a status + change. +3. **Teammate**, only when there is no `research.md`. `Agent` with + `subagent_type: task-executor` and `name: `; the research-mode + prompt carries: the key; the path of `source.md`; `$DIR/research.md` as the only + file it writes; the clone and `SHA`, read-only; the scout's facts and forks + verbatim; the path of `docs/PIPELINE.md`, whose section «Epics» is the contract + of the document; the language Russian, Markdown with `mermaid` diagrams without + `style`, `classDef`, `linkStyle`, `%%{init`; a header paragraph naming «Версия 1», + the date and the full `SHA`; every proposal with its alternatives and one line + `**Рекомендация:**` with the reason; every subtask the size of one PR, its + `**Проверки:**` the project's checks by «Checks» plus its own; the section + «Решения по независимой проверке» in version 1 only the header row and the + separator of the table; the rules: no worktree, no commits or any other Git + write, no diff, no derive, no task changes; its final message exactly one JSON + object by its definition, `commits` 0, `base` and `head` the `SHA`. Save its + report as `$DIR/do-report.json`. `openPoints` only the engineer can answer are a + question. +4. **Review**, one round. A fresh `task-reviewer` with the paths of + `$DIR/research.md` and `source.md`, the clone and `SHA`, the section «Epics» of + `docs/PIPELINE.md` in place of a plan, and the brief: review the document, not a + diff — every `repo:` citation exists on `SHA` and says what is claimed, every + `home:` one exists; the required sections and the fields of the subtasks by + «Epics»; every proposal has an alternative and one recommendation; nothing beyond + the request without a mark saying so; the final message one JSON object. Save + `$DIR/review-report.json`. Blocking findings and advice go to the teammate + verbatim by `SendMessage`: it fixes the blocking ones and applies advice when it + does not change a recommendation. The lead checks the fixed places against the + `fix` of each blocking finding by reading; there is no second review round. A + blocking finding the teammate cannot fix is a question. +5. **Publish version 1** as step 6 «Per key» of `.claude/skills/plan/SKILL.md`, with + the research files: `stage` with `target: "doc"` and no `short_id`; + `curl -sS -F file=@$DIR/research.md -F title=" — исследование: " `; + `organize` with `short_ids: []`, `set: ["", "", "research"]`; + write `$DIR/research-derive.json` `{"short_id","url","version","published_at"}`; + `read` with `render: "full"` — a diagram that did not render is named in the + report and fixed in version 2. No `derive.json`. Then + `$BIN/mp-task status planning "исследование v1 опубликовано: "`; + `$BIN/mp-home-commit ": research v1"`. + +## Step 2 — independent check + +Row 2. A fresh `plan-challenger` subagent with only: the path of `source.md` (the +verbatim request), the path of `$DIR/research.md` and its URL, the clone and the +`SHA` from the research's header, the paths of `docs/PIPELINE.md`, `AGENTS.md`, +`.claude/skills/` and `.claude/agents/` of the clone; never the scout's facts, the +review or the lead's conclusions. Its JSON goes verbatim into +`$DIR/challenge-report.json`. Not one JSON object with `main_sha_checked` and +`findings` (at most 12, each with `id`, `type`, `now`, `proposal`, `gain_loss`, +`reasoning`) → one more fresh run with the defect named; a second failure is a +question. `$BIN/mp-home-commit ": independent check"`. Zero findings → +step 4 at once. + +## Step 3 — decisions + +Row 3 (`ROWS` < `N`). For each finding of `challenge-report.json` in order whose `id` +has no row in the table «Решения по независимой проверке», one `AskUserQuestion`: +header `Находка `; in the text the type and verbatim `Что сейчас: `, +`Предложение: `, `Что выигрываем / что теряем: `, +`Обоснование: `; options «Принять» and «Отклонить», the lead's +recommendation first with `(рекомендую)`, one line of reasoning each; a comment +comes as a free answer. Right after the answer the lead appends to the end of the +table the row +`| | <находка> | | <принято|отклонено|комментарий: «<дословно>»> | |` +(`<находка>` is `proposal` as one short line without `|`) and runs +`$BIN/mp-home-commit ": finding "`; then the next question. The +decisions are written nowhere else: not in `progress.md`, not in `progress`. + +## Step 4 — version 2 + +Row 4 (`ROWS` = `N`, `V` = 1). The teammate (`SendMessage`; not alive — spawn it by +«State») gets the path of `challenge-report.json` and the rows of the table +verbatim; it applies the accepted findings, and the commented ones by their +comment, to the sections; the rejected ones change no text; it fills «Что +изменилось» of every row; under the table — where the subtasks of version 1 went; +with no findings — the line «Находок нет»; the header «Версия 2, <дата>»; the other +rules of step 1. Its report is `$DIR/do-report.json`. The lead checks that `ROWS` = +`N` and the last column of every row is filled. Publication: `stage` with the +`short_id` from `research-derive.json`, the same `curl` with +`-F message="v2: независимая проверка — находок, решения инженера в разделе «Решения по независимой проверке»"`, +update `research-derive.json` (the version from the answer), `read` with +`render: "full"`. No review of version 2. +`$BIN/mp-home-commit ": research v2"`. + +## Step 5 — subtasks + +Row 5 (`V` ≥ 2, no subtasks). + +1. One `AskUserQuestion`, header `Подзадачи`: in the text the list of the section + «Подзадачи» (number, title, goal, dependencies, stand), the line + `**Приёмка эпика:**` and the proposed flow name `` — the output of + `$BIN/mp-task slug `; options «Завести и запустить /flow (рекомендую)» + (creates the subtasks and runs `/flow ` here), «Завести» (creates + them; the engineer types `/flow`), «Поправить список» (an edit of the list). A + free answer that is one flow name alone is «Завести и запустить /flow» with that + name; any other free answer is «Поправить список» with that text as the edit. +2. **«Поправить список».** The edit is the free answer; when the option is chosen + without text, the lead asks for the edit in the chat and the engineer's next + message is its text. The teammate edits only the section «Подзадачи»; the lead + publishes the next version (`stage` with `short_id`, `curl` with + `-F message="v: список подзадач поправлен — <кратко>"`), updates + `research-derive.json`, `$BIN/mp-home-commit ": research v"`; + the question again. +3. **«Завести …».** For each subtask in the order of the section, a card in a + temporary file of the session's scratchpad: `# <название>`; the line + `Подзадача эпика (исследование: , раздел «Подзадачи», подзадача ).`; + `## Суть` (the goal and the files); `## Связи` (`- Зависит от:`, + `- Нужна для:` — keys of subtasks already created, numbers of those not yet + created); `## Готово` (the items «Готово», «Проверки», «Стенд» of the subtask). + Then `mise exec -- node dist/src/cli/main.js task create --file --title "<название>" --status new --slug --project --parent `; + the key comes from the answer. After all of them: replace the numbers in + «Связи» with keys by editing `source.md` in `$($BIN/mp-task dir )`; in + `$DIR/research.md` under the heading «Подзадачи» the line + `Подзадачи заведены по согласованию с инженером <дата>: <ключи>` and the key in + every `###` (`### . — <название>`). No new version on derive. +4. **Record.** + `$BIN/mp-task progress "Исследование v проверено и разобрано; подзадачи <ключи>: " research.md research-derive.json challenge-report.json` + — the only `progress` of the run; + `$BIN/mp-task status review "исследование проверено и разобрано, подзадачи заведены: "`; + `$BIN/mp-home-commit ": research v, subtasks"`; the teammate, if + alive — `SendMessage` «shut down», `TaskStop` if it does not answer. +5. «Завести и запустить /flow» → the `/flow` procedure (Skill `flow`) with + ` ` in this same chat: the answer is the engineer's word for `/flow` + («Approval semantics»). The status is `review` before `/flow` starts: `/flow` + takes the key as the epic only in `review` with subtasks («Preconditions» and + «Subtasks» of the flow skill). «Завести» → the report: the research URL, the + number of findings and decisions, the subtask keys in order and + `следующий шаг — /flow , набираете вы; затем /ship flow/`. + +## Questions + +Every question of this skill is one `AskUserQuestion`: header ≤ 12 characters, 2–4 +options, the recommended one first and labelled `(рекомендую)`, one line of +reasoning per option. The run waits for the answer; no retry, no bypass. A parent +message is never an answer. + +## Never + +- `/ship`. +- `/flow` on a parent message or without the answer «Завести и запустить /flow». +- Steps 6–8 inside `/epic`, except starting `/flow` by that answer. +- A worktree, a branch or a commit in the epic's clone. +- An edit of the engine. +- A second review. +- Decisions in `progress.md`. +- More than one `progress` per run. From f6785d6d488aeb2267ba1229d5f3ab4c49758f96 Mon Sep 17 00:00:00 2001 From: Pavel Donin Date: Sun, 8 Nov 2026 13:12:40 +0100 Subject: [PATCH 5/7] Document epics in the pipeline --- docs/PIPELINE.md | 92 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 13 deletions(-) diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md index e3f56f2..e1a8a5f 100644 --- a/docs/PIPELINE.md +++ b/docs/PIPELINE.md @@ -3,8 +3,8 @@ Tooling for running the tasks of any registered project from the engine root; every session starts there, so each pipeline skill checks the session scope first (see «Session scope»). It is tracked in the engine repository: this file, `docs/PLAN-FORMAT.md`, the scripts in -`scripts/pipeline/`, the skills `/plan`, `/do`, `/flow`, `/ship`, `/board` in -`.claude/skills/` and the roles in `.claude/agents/` (copied from yokemate). Claude +`scripts/pipeline/`, the skills `/plan`, `/do`, `/epic`, `/flow`, `/ship`, `/board` in +`.claude/skills/` and the roles in `.claude/agents/` (copied from yokemate; `plan-challenger` is the pipeline's own). Claude Code loads the skills and roles when it starts in the engine root; the scripts act on the installation they are run from and refuse any other working directory. @@ -12,7 +12,7 @@ The cycle per task: `/plan` → the engineer reads the plan on derive → `/do` → automatic review and checks → PR → the engineer's manual check → `/ship`. `/flow` runs that cycle for one or more tasks of one project, one task at a time, asks the engineer at every decision and merges the tasks into one flow branch the -engineer checks as a whole. In this file «flow» alone is that run; the project's +engineer checks as a whole. An epic goes `/epic ` → `/flow ` → `/ship flow/` («Epics»). In this file «flow» alone is that run; the project's flow is the project's branch and merge settings (`flow.json`, `mp-task flow`). ## Places @@ -38,7 +38,7 @@ flow is the project's branch and merge settings (`flow.json`, `mp-task flow`). the folder may be edited. `task progress … ` commits the named files in home and records each as `{path, commit}`: the entry always reads the version it registered (`mypi context read --revision `). Registered directly: - `plan.md` (`/plan`); `plan.md`, `pr.md`, `do-report.json`, `review-report.json` + `plan.md` (`/plan`); `research.md`, `research-derive.json`, `challenge-report.json` (`/epic`); `plan.md`, `pr.md`, `do-report.json`, `review-report.json` (`/do`); `pr.md`, `progress.md` (`/ship`). A card is corrected by editing `source.md` and running `mp-home-commit`. The `plan-v.md`, `*-final.md` and `addendum.md` files of earlier tasks remain @@ -61,7 +61,7 @@ flow is the project's branch and merge settings (`flow.json`, `mp-task flow`). ## Session scope Every session (the main chat, an organization chat, a project chat, a task chat) starts in the engine root -and sees the pipeline skills. Each of the five skills checks the session scope as its +and sees the pipeline skills. Each of the six skills checks the session scope as its Step 0. The key: `scripts/pipeline/mp-task scope` prints `{"key", "project", "org", "codes", "source"}`. @@ -77,14 +77,14 @@ nor `inbox` is used for the check, because both mark events delivered. The rule: -- `global`: `/plan`, `/do` and `/ship` take tasks of any project; `/flow` and +- `global`: `/plan`, `/do`, `/epic` and `/ship` take tasks of any project; `/flow` and `/ship flow/` take the keys of one project. -- `O` (an organization): `/plan`, `/do` and `/ship` take keys whose code is in +- `O` (an organization): `/plan`, `/do`, `/epic` and `/ship` take keys whose code is in `codes`; `/flow` and `/ship flow/` take the keys of one project from `codes` (the flow score lives in that project's home). - `P` (any project): every typed key has the code `P`; a flow holds keys of `P`, `/ship flow/` takes a flow of project `P`. -- `P-N`: `/plan`, `/do`, `/flow` and `/ship` take P-N and its subtasks — every task +- `P-N`: `/plan`, `/do`, `/epic`, `/flow` and `/ship` take P-N and its subtasks — every task whose chain of parents reaches P-N (`mp-task subtasks P-N`); `/ship flow/` — when every key of the flow score `/flows/.md` is P-N or its subtask. - A typed argument that is not a key `CODE-N` (other than `flow/` of `/ship` @@ -109,7 +109,7 @@ arguments and `` substituted): - `/board` with a malformed key: `The board cannot tell this session's project (scope ). Open the main chat with /open global.` - `/board` with an unknown code: `Unknown project code

; registered codes: .` - a changing skill with another project's key: `/ is not allowed in session scope ; nothing was written. This chat runs tasks of

only; run it in that task's or project's chat (/open ) or in the main chat (/open global).` - (`` is the code of the typed key.) In a `P-N` chat append: ` This chat may run /plan, /do, /flow and /ship for P-N and its subtasks (|none) only.` + (`` is the code of the typed key.) In a `P-N` chat append: ` This chat may run /plan, /do, /epic, /flow and /ship for P-N and its subtasks (|none) only.` - a changing skill in an organization with a key outside `codes`: `/ is not allowed in session scope ; nothing was written. This chat runs tasks of only; run it in the main chat (/open global).` - a non-zero exit of `mp-task subtasks`: `/ cannot read the subtasks of : ; nothing was written.` - `/ship flow/` in a `P-N` chat without the flow score: `/ship flow/: no flow score ; nothing was written.` @@ -155,6 +155,66 @@ parent that last sent the subtask a message, else the project chat (`src/app/task-work.ts`). The events of a task's session still go to the Parent whose message started the turn, else the project chat. +## Epics + +An epic is a task whose research proposes a mechanism and its subtasks. +`/epic ` (`.claude/skills/epic/SKILL.md`) leads steps 1–5 in the epic's chat: +research, independent check (`plan-challenger`), the engineer's decision on each +finding, version 2, subtasks. `/flow ` runs steps 6–8 (the epic key +and the epic acceptance of «Subtasks» above), started by the engineer's answer in +`/epic` or typed; `/ship flow/` merges. The step comes from the epic's status +and the files of its folder; there is no epic status, field or engine command. + +`DIR` is `scripts/pipeline/mp-task dir `; `N` — +`python3 -c 'import json,sys;print(len(json.load(open(sys.argv[1]))["findings"]))' $DIR/challenge-report.json`; +`ROWS` — `awk '/^## .*Решения по независимой проверке/,/^## Источники/' $DIR/research.md | grep -c '^| [0-9]'`; +`V` — `python3 -c 'import json,sys;print(json.load(open(sys.argv[1]))["version"])' $DIR/research-derive.json`. +The first row from the top whose sign holds is the step: + +| Sign | Step | Next | +| --- | --- | --- | +| status `new`, no `research.md` | 1, not started | `/epic `: research | +| `research.md`, no `research-derive.json` | 1, under way | `/epic `: review, version 1 published | +| `research-derive.json`, no `challenge-report.json` | 2 | `/epic `: independent check | +| `ROWS` < `N` | 3 | `/epic `: a question on each remaining finding | +| `ROWS` = `N`, `V` = 1 | 4 | `/epic `: version 2 | +| `V` ≥ 2, `mp-task subtasks ` empty | 5 | `/epic `: the «Подзадачи» question | +| `mp-task subtasks ` not empty | 6–8 | `/flow `, then `/ship flow/` | + +Statuses of an epic: `new` while the research is written; `planning` with the +research URL once version 1 is published; `review` once the subtasks are +created; `done` is the engineer's word. An epic researched by `/plan` and `/do` +before `/epic` existed reads the same: the signs are files, not their author. + +The research, `research.md`: Markdown with `mermaid`, in Russian; its header +paragraph names the version, the date and the full SHA of the clone's +`origin/` it was written on. The later steps read these sections, +so they are required; everything else is free: + +- `## . Итог`; +- `## . Подзадачи`: the line `**Приёмка эпика:** да: ` or + `нет: ` — whether the epic as a whole is accepted on a stand and by + what criterion; then each subtask in order as `### . ` (after + creation `### <N>. <KEY> — <title>`) with one-line fields `**Цель:**`, + `**Файлы:**`, `**Документация и карта:**`, `**Зависимости:**`, `**Готово:**`, + `**Проверки:**`, `**Стенд:**`; +- `## <n>. Решения по независимой проверке`: the table + `| # | Находка | Тип | Решение инженера | Что изменилось |`, no rows in + version 1, one row per finding of `challenge-report.json` added by `/epic` + right after each answer, the last column and the line on where the subtasks + of version 1 went filled by version 2; «Находок нет» when there are none; +- `## Источники`. + +The epic's folder: `source.md`; `research.md`; `research-derive.json` +(`{"short_id","url","version","published_at"}`); `do-report.json` (the +`task-executor` teammate, which writes `research.md` in the folder: no worktree, +no commits, no diff); `review-report.json` (one `task-reviewer` round on +version 1); `challenge-report.json` (the `plan-challenger` answer, verbatim); +`acceptance.md` and its evidence (the epic acceptance, «Subtasks»). The journal gets one +`progress` per `/epic` run, at step 5, with `research.md`, +`research-derive.json` and `challenge-report.json`; the decisions live only in +the table. + ## Temporary scripts Two of the three scripts stand in for mypi features the v2 plan adds later; each @@ -175,19 +235,20 @@ so: Subagent types from `.claude/agents/`: `plan-scout` (read-only reconnaissance), `plan-writer` (writes `plan.md` by `docs/PLAN-FORMAT.md`), `task-executor` (implements one task in its worktree), `task-reviewer` (fresh-eyes review of a diff against the -plan), `task-investigator` (one question about existing behaviour, read-only). +plan), `task-investigator` (one question about existing behaviour, read-only), +`plan-challenger` (read-only independent check of a research document against the engineer's verbatim request; `/epic`). The executor runs as an in-process **teammate** named by the key in lower case (`mp-33`), spawned with `subagent_type: task-executor` and `name`. It stays alive through the review loop, so reviewer findings go to it by `SendMessage` and it fixes -in the same context. Reviewer and investigator are ordinary subagents: fresh +in the same context. Reviewer, investigator and challenger are ordinary subagents: fresh context every time, never the lead's conclusions. When a task reaches `review` the lead asks the teammate to shut down. Under `/flow` it does so after the key is recorded in the flow score. What every executor prompt carries: the task key, the plan path, the worktree path, the task folder path, the base branch, this file's path, and the rule that its -final message is exactly one JSON object per its definition. +final message is exactly one JSON object per its definition. Under `/epic` the epic's folder and the clone's SHA take the place of the worktree and the base branch («Epics»). ## Statuses in mypi @@ -238,7 +299,7 @@ One writer per fact; nothing is written twice. one `progress` entry (`mp-task progress`: a `note` with the step's files as artifacts) at its «Record» step: `/plan` the published plan (`plan.md`), `/do` the PR or the flow merge (`plan.md`, `pr.md`, `do-report.json`, - `review-report.json`), `/ship` the merge (`pr.md`, `progress.md`). Every + `review-report.json`), `/ship` the merge (`pr.md`, `progress.md`), `/epic` the checked research and its subtasks (`research.md`, `research-derive.json`, `challenge-report.json`). Every status reason carries the relevant link («Statuses in mypi»); a reason set by `/flow` itself or by `/do` stage 1 in flow mode starts with `в потоке <name>`. `/flow` writes no `progress` of its own: its record is the flow score. @@ -259,6 +320,11 @@ One writer per fact; nothing is written twice. - An approved plan is the engineer typing `/do <KEY>` or `/flow …`; under `/flow` the engineer's answers to the plan's forks are part of the approval. No other signal counts; a published plan queues nothing. +- Typing `/epic <KEY>` authorizes the research, its publication on derive and, + after the engineer's answer to the «Подзадачи» question, `mypi task create + --parent <KEY>` for the agreed subtasks. The answer «Завести и запустить /flow» + in the epic's chat equals typing `/flow <name> <KEY>`; `/ship` runs only when + typed. A parent message is never an answer to these questions. - Open comment threads on the plan artifact (`catch_up` with `comments: open`) are remarks. `/plan` reworks the plan and republishes, resolving each thread with `comment` and `set_state: resolved` and a reply saying what changed. `/do` refuses to start while a thread is open, unless typed with From cc4df6ffa3461f3dc47c37db1743b7add41ed177 Mon Sep 17 00:00:00 2001 From: Pavel Donin <doninpr@proton.me> Date: Sun, 8 Nov 2026 13:12:54 +0100 Subject: [PATCH 6/7] Name /epic in the map, README, task role and changelog --- AGENTS.md | 2 +- CHANGELOG.md | 1 + README.md | 2 +- integrations/prompts/task.md | 2 +- test/fixtures/warmup/MP-12.md | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index fc333f7..30c02a4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -123,7 +123,7 @@ Before acting in an area, read its document; it binds like this file. - sessions, /open, events, parent messages → [sessions](docs/agents/sessions.md) - `mypi serve`, API tokens, the TUI → [HTTP API](docs/agents/http-api.md) - projects → [project-management skill](integrations/skills/project-management/SKILL.md) -- /plan, /do, /flow, /ship, /board → [pipeline](docs/PIPELINE.md) +- /plan, /do, /flow, /ship, /board, /epic → [pipeline](docs/PIPELINE.md) - [architecture](docs/ARCHITECTURE.md), [testing](docs/TESTING.md), [stand acceptance](docs/MANUAL-ACCEPTANCE.md) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0f8169..4ee9bba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ from existing transcripts. MEMORY.md is no longer read; move facts into INDEX.md - Journal facts of the engine (MP-88): five event types — `worktree_created` (task scope, `task worktree` when it creates the worktree: `worktree <path>, branch <branch>, base <integration>`), `session_opened` (task, project or organization scope, `/open` when it starts or resumes a session: `started <agent>` / `resumed <agent>`, with `, worktree <path>` for a task; nothing on focus), `message_sent` (the recipient's scope, every accepted parent message: `message <id> from <parent>: <first line, up to 120 characters>`), `title_changed` (task scope, a task rename; the text `Title: "a" → "b". <reason>` is unchanged) and `clone_prepared` (project scope, a checkout cloned, initialized or adopted by `/open`: the same text as its `notes` line). The list lives once in `EVENT_TYPES`; `journal read --type`, MCP `journal` and `GET /v1/journal?type=` accept the new types. A type other than note is accepted only in the scopes of its fact. `mypi project remove` now refuses a project that was opened (`session_opened`) or cloned by `/open` (`clone_prepared`), because those entries are project-scope journal rows and journal rows block removal. - Journal in the warmup (MP-91): a project warmup ends its tail with «Журнал» — the number of journal entries of the project and all its tasks with the local date of the newest one («Записей в журнале проекта нет.» when none) — and a task warmup with the task's last five entries in the journal line format (date, time, type, text up to 300 characters, artifacts; «Записей в журнале задачи нет.» when none); both name the `journal` call with `limit` 20 and its CLI form. Over the budget a task warmup drops the shown entries from the oldest before clipping knowledge entries, and after the knowledge entries clips the end of its card with a pointer to `context_read`, so a long card no longer pushes the Claude hook past 10,000 characters; the project line, the task heading with its count and the loader are never cut. The counts come from one SQL statement of the journal store (`stats`, `last`), not from a scope-resolving read, so the Claude hook stays fast. - Organization scope and chat (MP-78): the bare organization slug (`tb-ff`) is a session key. `/open tb-ff` (MCP `open_session`, CLI `mypi open`) opens, focuses or resumes the organization chat in the Herdr tab `org-tb-ff` of the workspace `tb-ff`, in the engine root, with no clone or worktree; `global`, `all`, an unknown organization and an organization without registered projects are refused. The organization chat leads the tasks of all registered projects of its organization: it opens their task chats and sends them parent messages directly. Its warmup (role `org`) carries the global and organization knowledge entries, one line per project and the events addressed to it; its start message lists each project's open tasks by status. Pi completes `/open` with the organization's projects and their open tasks; the pipeline skills accept the organization scope (`mp-task scope` adds `org` and `codes`). +- Skill `/epic` and role `plan-challenger` (MP-107: MP-109): `/epic <KEY>` reads the epic's step from its status and folder (`docs/PIPELINE.md`, «Epics») and leads research, one review round, publication, an independent check by the read-only role `plan-challenger`, one question per finding with its decision row, version 2 and the subtasks created with `--parent`; the answer «Завести и запустить /flow» runs `/flow <name> <KEY>`. Claude Code only, through `.claude/skills/epic` and `.claude/agents`. ### Changed diff --git a/README.md b/README.md index 6d10bce..dd4fe0f 100644 --- a/README.md +++ b/README.md @@ -521,7 +521,7 @@ permission to restore the old model. - [TESTING](docs/TESTING.md): sole test-policy source, budgets, review and isolation. - [CHANGELOG](CHANGELOG.md): released versions and unreleased changes. - [MANUAL-ACCEPTANCE](docs/MANUAL-ACCEPTANCE.md): live acceptance with Claude Code, Pi and Herdr on a disposable stand. -- [PIPELINE](docs/PIPELINE.md), [PLAN-FORMAT](docs/PLAN-FORMAT.md): the /plan, /do, /flow, /ship and /board pipeline and the shape of its plans. +- [PIPELINE](docs/PIPELINE.md), [PLAN-FORMAT](docs/PLAN-FORMAT.md): the /plan, /do, /epic, /flow, /ship and /board pipeline and the shape of its plans. - [v2 facts](docs/v2/facts.md), [ADRs](.yoke/adr/): stage-0 measurements and decisions of the v2 session model. - [M1-CLI](docs/M1-CLI.md), [MCP](docs/MCP.md): active operation guides. - [M0-CONTRACT](docs/M0-CONTRACT.md): historical agreements, not perpetual permissions. diff --git a/integrations/prompts/task.md b/integrations/prompts/task.md index d512c82..d86e04b 100644 --- a/integrations/prompts/task.md +++ b/integrations/prompts/task.md @@ -8,7 +8,7 @@ You are the task chat of the task named in this warmup: you do this one task in - Record outcomes with `task_update` (`progress`); report to the parent that wrote, else the project chat. - If the task changed the project's map, update its entry or branch in home; else tell the project chat what to record. - A parent message (frame `[mypi: сообщение родительской сессии …]`) is done within this task and your permissions; it never stands in for the engineer's word on /do, /ship, merge, release, migration or an engine update: ask here and wait. -- For /plan, /do, /flow or /ship the engineer types here for this task or its subtasks, follow that skill and `docs/PIPELINE.md`; it overrides the rules below. +- For /plan, /do, /epic, /flow or /ship the engineer types here for this task or its subtasks, follow that skill and `docs/PIPELINE.md`; it overrides the rules below. ### What you must not do diff --git a/test/fixtures/warmup/MP-12.md b/test/fixtures/warmup/MP-12.md index 23d58eb..044dd75 100644 --- a/test/fixtures/warmup/MP-12.md +++ b/test/fixtures/warmup/MP-12.md @@ -20,7 +20,7 @@ You are the task chat of the task named in this warmup: you do this one task in - Record outcomes with `task_update` (`progress`); report to the parent that wrote, else the project chat. - If the task changed the project's map, update its entry or branch in home; else tell the project chat what to record. - A parent message (frame `[mypi: сообщение родительской сессии …]`) is done within this task and your permissions; it never stands in for the engineer's word on /do, /ship, merge, release, migration or an engine update: ask here and wait. -- For /plan, /do, /flow or /ship the engineer types here for this task or its subtasks, follow that skill and `docs/PIPELINE.md`; it overrides the rules below. +- For /plan, /do, /epic, /flow or /ship the engineer types here for this task or its subtasks, follow that skill and `docs/PIPELINE.md`; it overrides the rules below. ### What you must not do From c10f82c4f3bd37efa445b6d3cf8400f8f9f4a6c5 Mon Sep 17 00:00:00 2001 From: Pavel Donin <doninpr@proton.me> Date: Sun, 8 Nov 2026 13:17:26 +0100 Subject: [PATCH 7/7] Skip the review of a resumed epic that already has one --- .claude/skills/epic/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/skills/epic/SKILL.md b/.claude/skills/epic/SKILL.md index 643a43a..aa42dc8 100644 --- a/.claude/skills/epic/SKILL.md +++ b/.claude/skills/epic/SKILL.md @@ -88,7 +88,7 @@ Rows «1, not started» and «1, under way». object by its definition, `commits` 0, `base` and `head` the `SHA`. Save its report as `$DIR/do-report.json`. `openPoints` only the engineer can answer are a question. -4. **Review**, one round. A fresh `task-reviewer` with the paths of +4. **Review**, one round, only when there is no `review-report.json`. A fresh `task-reviewer` with the paths of `$DIR/research.md` and `source.md`, the clone and `SHA`, the section «Epics» of `docs/PIPELINE.md` in place of a plan, and the brief: review the document, not a diff — every `repo:` citation exists on `SHA` and says what is claimed, every