From 8987ec460b41970eaa2b356ade2b5f8c197d6675 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 23:53:17 +0000 Subject: [PATCH] batch: make /batch a conversational door, not a command wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skill was a thin wrapper — "run batch plan, return the decision" — which is enough to read a proposal and nothing like enough to run a slot from a chat. This is the body: skills/batch/batch.md, with SKILL.md pointing at it, matching the repo's own convention. It covers the three things a human actually says, rather than the one verb the CLI exposes: "What should I run?" -> the BatchDecision as written, with the two parts that must survive into the reply: the review-minute total, and the other lane's ready count when this session cannot plan it. "Here are the ones I want." -> a paste of dashboard paths, or a description. Resolve, run the constraints over exactly that set, and report per task what was taken and what was rejected IN THE PLANNER'S OWN WORDS. Never silently substitute different picks; if everything they named is rejected, say so and offer the planner's proposal as an alternative rather than as though it were the ask. "Go." -> vitals, the Heart reason set recorded verbatim, the batch record written BEFORE any session starts, then one session per member. Two overrules are refused: an open Blocked-by, and Unattended: never. Everything else the human may overrule, provided the reply names which rejection is being overruled. The return path is the half that was missing entirely: read the PRs failures-first, offer merge / tweak / reject, and on a tweak DRAFT THE FOLLOW-UP PROMPT so the human never has to write a prompt file. Then get review-minutes-actual, asking for it if it is not volunteered — it is the only calibration the whole estimate ever gets. Two guards restated where they will actually be read: the independent adversary leg must have run, in a session using a different model, BEFORE any PR from a batch is reviewed; and `delivered:` is not "green", because a cloud session's green status means it exited without an infrastructure error, not that the task succeeded. 119 lines against the 200-line mandatory-load budget. 691 tests pass. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01RQeMJZznA3xTQXX4PqWg1v --- skills/batch/SKILL.md | 23 ++++------ skills/batch/batch.md | 102 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 14 deletions(-) create mode 100644 skills/batch/batch.md diff --git a/skills/batch/SKILL.md b/skills/batch/SKILL.md index 8f76a38..f16c4e8 100644 --- a/skills/batch/SKILL.md +++ b/skills/batch/SKILL.md @@ -5,18 +5,13 @@ description: Compose the next unattended batch through the PyAutoBrain Batch Age # Batch -Read [`../../agents/conductors/batch/AGENTS.md`](../../agents/conductors/batch/AGENTS.md) -completely, then run `bin/pyauto-brain batch plan` in the documented mode. +Read [`batch.md`](batch.md) in this directory — the authoritative body for the +slot door: how to propose a batch, how to compose one from what the human +pasted or described, how to dispatch it, and how to work through what came +back. Then read +[`../../agents/conductors/batch/AGENTS.md`](../../agents/conductors/batch/AGENTS.md) +for the constraints and why each exists. -Return the **BatchDecision** as written — members, the review-minutes it spends, -and what it rejected with reasons. Do not re-rank it, do not quietly add a -member the planner excluded, and do not present it as a schedule: it is a -proposal, and the human approving it in their slot is what launches the batch -([`../../AUTONOMY.md`](../../AUTONOMY.md), "What a batch launch is"). A -scheduler may carry the timing; it never carries the authority. - -Two parts of the output are the point and must survive into your reply: the -**review-minute total** (the budget is the human's hour, not a task count), and -the **other lane's ready count** when the session cannot plan it — *"4 local-dev -tasks are ready, run this from the laptop"*. An empty batch at the backpressure -cap is a finding, not a deadlock; say which. +The one rule that outranks convenience: **the human's go in the conversation is +what launches a batch** (`../../AUTONOMY.md`, "What a batch launch is"). A +schedule may carry the timing; it never carries the authority. diff --git a/skills/batch/batch.md b/skills/batch/batch.md new file mode 100644 index 0000000..8c6a2a6 --- /dev/null +++ b/skills/batch/batch.md @@ -0,0 +1,102 @@ +# Batch — the slot door + +The front door for the two-slot workflow: **what runs unattended, and what came +back**. Drive it from a chat; nothing here needs a terminal. + +Read [`../../agents/conductors/batch/AGENTS.md`](../../agents/conductors/batch/AGENTS.md) +before acting — it holds the constraints, why each exists, and the full slot +procedure. This page is how to *converse* with it. + +## The three things a human says + +**1. "What should I run?"** — `/batch`, or any ask for the next batch. + +Run `bin/pyauto-brain batch plan` and return the **BatchDecision as written**. +Do not re-rank it. Do not quietly add a member it rejected. Two parts must +survive into your reply because they are the point of the whole surface: + +- the **review-minute total** — the budget is the human's hour, not a task count; +- the **other lane's ready count**, when this session cannot plan it: *"4 + local-dev tasks are ready — run this from the laptop."* + +An empty batch at the backpressure cap is a **finding, not a deadlock**: nothing +in the backlog costs zero review-minutes. Say which it is. + +**2. "Here are the ones I want."** — a paste of paths from the Mind dashboard, +or a description ("something on the numba path", "the next euclid slice"). + +Resolve what they gave you to prompt paths, then run the planner's constraints +over exactly that set — do not silently substitute your own picks. Report, per +task they named: + +- **taken** — with its tier and review-minutes; +- **rejected, and why** — in the planner's own words. The reasons that come up + most: `autonomy supervised — would park at ship` (it will stop at the ship + checkpoint and come back as a question, which is the failure this workflow + exists to remove), `Status: says the work is already done`, `epic phase + N is not next`, ` already claimed this shift`, `would exceed the budget`. + +If everything they named is rejected, **say so plainly and offer the planner's +own proposal instead** — never hand back a batch they did not ask for as though +it were what they wanted. + +The human may overrule any rejection except two: a `Blocked-by:` that is still +open, and `Unattended: never`. Those are not preferences. + +**3. "Go."** — the dispatch. This is the launch, and it is the human's act +(`AUTONOMY.md`, "What a batch launch is"): membership fixed at approval, the +grant expiring with the shift. Never dispatch on your own initiative, on a +schedule, or because a batch looks ready. + +In order: + +1. Consult vitals (`bin/pyauto-brain vitals`). If Heart is YELLOW, **ask the + human to acknowledge the reason set for this shift** and record it verbatim. + You may not acknowledge it for them, and a set carried from an earlier batch + is void. +2. Write `PyAutoMind/batches/-.md` from the schema in that + folder's `AGENTS.md` — members, planned review-minutes, the reason set — + **before** any session starts. That file is what makes the launch auditable. +3. Start one session per member, each carrying exactly + `/start_dev --auto`. Spawn them if this harness can; otherwise hand + the human the lines to paste. **One session per member, never shared**: a + shared session serialises them and carries one member's context into the + next. +4. Confirm what was dispatched, and stop. Do not follow the runs. + +## When they come back + +Read the PRs. Order: **failures first, then anything labelled `decision-taken`, +then clean.** For each, offer three things and do the one they pick: + +- **merge** — `/prm `; +- **tweak** — they say one line; *you* draft the follow-up prompt and put it at + the top of `queue.md`. They should never have to write a prompt file. +- **reject** — route it to `condemned.md`. + +Then append the outcome to the batch record: `delivered:` (see below) and +**`review-minutes-actual:`**. That second number is the only calibration the +estimate will ever get, so ask for it if the human does not volunteer it. + +**Before reading any PR from a batch, the independent adversary leg must have +run** (`AUTONOMY.md` leg 5): `bin/pyauto-brain review --task --witness +"" --adversary`, **in a session using a different model +from the one that wrote the branch**. A self-run adversary leg is an absent leg, +not a weak one, and recording it as run is a false ledger row. If it has not +run, say so rather than reviewing as though it had. + +**`delivered:` is not "green".** A cloud session's green status means it exited +without an infrastructure error — not that the task succeeded. A member counts +as delivered only with a PR that has a non-empty diff and checks that ran. A +member that ended green with no PR is reported **not delivered**, loudly, at the +top. + +## Never + +- Dispatch without an explicit go from the human in this conversation. +- Acknowledge a Heart YELLOW or RED on their behalf, or reuse a previous + shift's reason set. +- Add a member the planner rejected without saying which rejection you are + overruling and why. +- Present the proposal as a schedule. The schedule may carry the timing; it + never carries the authority.