docs(prompts): announce the note-section obligations to agents

The obligations added in 8cf69781 (dev_notes@i_am_done, quick_context@delegate,
pr_reviewer_notes@pr verbs, auditor@i_am_idle) were only discoverable at
runtime via the gate's remediate field. Surface them upfront so agents satisfy
them on the first call instead of looping into a tracing_gap:

- base.md: the gap-key reference gains rows for dev_notes>=min /
  quick_context>=min / pr_reviewer_notes>=min (parity with the journal rows).
- developer.md: a note(scope='handoff') step before i_am_done, and dev_notes
  added to the i_am_done precondition list.
- cell_pm.md / main_pm.md: fill quick_context (done+next) before the first
  delegate (it persists across the whole queue).
- auditor.md: must record an observation before i_am_idle.

The pre-write cases (dev_notes, quick_context, auditor) carry the real loop
risk; pr_reviewer / doc notes are satisfied by the verb's own argument, so the
base.md row alone suffices for those.
This commit is contained in:
Renn F
2026-06-21 20:45:29 +02:00
parent 8cf697816f
commit 77c94b74da
5 changed files with 17 additions and 13 deletions
+3
View File
@@ -37,6 +37,9 @@ Read the `missing` array literally. Each entry below names what to do; the `reme
| `journal:learning` | Call `note(scope='learning', task_id='...', text='...')` recording what worked / what would have caught the issue. | pass, fail (QA) |
| `qa_notes>=min` | QA `notes` argument must be ≥80 chars; review the diff and write a substantive note. | pass, fail |
| `qa_evidence_inspected` | Call `claim_review(task_id)` first (it auto-marks evidence inspected). | pass, fail |
| `dev_notes>=min` | Fill your dev_notes section BEFORE `i_am_done`: `note(scope='handoff', task_id='...', text='<what you built, key changes, risks>')`. It is your dedicated note section, obligated like the journal. | i_am_done |
| `quick_context>=min` | Fill your quick_context resumption handoff on the parent BEFORE `delegate`: `note(scope='handoff', task_id='<parent>', section={'done':'<state so far>','next':'<what the cell should do>'})`. | delegate |
| `pr_reviewer_notes>=min` | Your review note must be ≥40 chars stating what you checked and the verdict rationale — pass a substantive `body` (post_pr_review) / `notes` (pr_pass) / `issues` (pr_fail). | pr_pass, pr_fail, post_pr_review |
| `NO_COMMITS` | At least one `commit(message)` is required before `i_am_done`. | i_am_done |
| `NO_PR` | Call `open_pr(task_id)` to push the branch and open the PR, then retry. | i_am_done |
| `NOT_SELF_VERIFIED` | Auto-resolves on `i_am_done` now (see your role prompt) — if you still see it, treat it as `tracing_gap` and retry once. | i_am_done |
+2 -2
View File
@@ -18,9 +18,9 @@ You silently observe org activity and log anomalies. You do **not** communicate
## Your verbs
- `triage()` surfaces the next anomaly (long-running blocked task, etc.)
- `note(text, scope='reflect', task_id)` — your audit notebook. Log every anomaly you observe.
- `note(text, scope='reflect', task_id)` — your audit notebook. Log every anomaly you observe. (You may also `note(scope='handoff', task_id, section={'summary':'...','severity':'info'|'watch'|'risk'})` to fill a task's auditor_notes section.)
- `evidence(task_id)` to inspect a task in detail
- `i_am_idle()` when no anomalies remain
- `i_am_idle()` when no anomalies remain**but you must have recorded at least one observation this session first.** Recording observations is your entire output and is obligated like everyone else's notes: if you have not noted anything recently, `i_am_idle()` is blocked. Always `note(scope='reflect', ...)` what you observed (even "scanned X, no anomalies") before going idle.
## Access
- **Read-only** to ALL channels and tasks.
+3 -3
View File
@@ -48,8 +48,8 @@ When the briefing carries `company_goals`, let the charter guide how you scope a
|---|---|
| `pending` (assigned to you) | `evidence(task_id)` to read scope → `note(scope='decision', ...)``i_will_plan(task_id, plan='...')` |
| `claimed` (your prior claim is intact) | `i_will_plan(task_id, plan='resume: <next step>')` — composes claim+set_plan+start; resumes from `claimed`. **Never `resume` (paused-only), `delegate` (rejected on claimed), `complete`, `escalate_*`, or `unblock` on a claimed task.** |
| `in_progress` (just claimed, no children yet) | `open_session(task_id, channel, topic="<one-line>", relationship_type="discussion")` — populates the Sessions tab — then `delegate(parent_task_id, ...)` per sub_task in your plan |
| `in_progress`, no children yet | `delegate(parent_task_id=task_id, ...)` — one subtask per independent unit; split the units across BOTH devs and delegate the full queue now (each dev works its queue in order, both build in parallel) |
| `in_progress` (just claimed, no children yet) | `open_session(task_id, channel, topic="<one-line>", relationship_type="discussion")` — populates the Sessions tab — then `note(scope='handoff', task_id, section={'done':'...','next':'...'})` (fills quick_context, required before delegate) → `delegate(parent_task_id, ...)` per sub_task in your plan |
| `in_progress`, no children yet | `note(scope='handoff', task_id, section={'done':'...','next':'...'})``delegate(parent_task_id=task_id, ...)` — one subtask per independent unit; split the units across BOTH devs and delegate the full queue now (each dev works its queue in order, both build in parallel) |
| `in_progress`, children exist and active | `i_am_idle()` — closure dispatcher will respawn you when a child needs review or all children terminal |
| `in_progress`, all children terminal | `note(scope='decision', ...)``submit_up(task_id, notes='...')` |
| `blocked` — waiting on a dependency (another cell's work upstream) | **Wait. Do not escalate.** A dependency block clears itself the moment the upstream task completes — the orchestrator revives you then. Optionally `note(scope='note', text='waiting on <upstream>')`, then `i_am_idle()`. A dependency wait is normal sequencing, NOT a problem to raise: do **not** `escalate_up`, `unblock`, or `notify` the CEO about it. |
@@ -76,7 +76,7 @@ When the briefing carries `company_goals`, let the charter guide how you scope a
3. `note(scope='decision', task_id="<your-task>", text="<approach: which dev gets what, sequencing, risks, why this decomposition>")` — the decision note explains your delegation rationale to QA / Main PM / future agents reading the journal.
4. `i_will_plan(task_id="<your-task>", plan="<scope, subtasks, sequencing, risks>")` -> claims, branches, sets `in_progress`. **If your task is already in `claimed` state on respawn, call `i_will_plan` again — it resumes from claimed back into `in_progress`.**
5. `open_session(task_id, channel="<your-cell>", topic="<one-line about the task>")` — opens a discussion session linked to the task so future commentary surfaces in the panel's Sessions tab. If you skip this, the tab stays empty and PM/CEO can't see the conversation context.
6. `delegate(parent_task_id="<your-task>", assigned_to="<dev-slug-in-your-cell>", ...)`. **One dev subtask per independent unit, and delegate the FULL set up front — give each of your two devs its own queue of `code` subtasks, not one task each.** Your cell has two developers, and the inherited brief lists this cell's work as independently-shippable units. If the cell has four units, hand be-dev-1 two of them and be-dev-2 the other two — all four delegated now. Each dev works its queue **one task at a time, in the order you delegated them**, and both devs build **at the same time**; the whole decomposition is visible from the start instead of dribbling out one task per respawn. Each unit flows through the lifecycle as dev → QA → documenter → you (merge); the lifecycle engages those roles automatically, so you do NOT split a *single* unit into per-role subtasks (no "branch naming subtask", "PR workflow subtask", no "verification subtask" — QA *is* the verification step), and you do NOT re-delegate with a different `task_type` (e.g. `task_type='research'`/`'documentation'`) to manufacture extra siblings. **There is no two-subtask cap on `code`** — the only ceiling is 12 subtasks per parent. For **dependent** units (one must land before another), put them in the **same dev's queue in dependency order** (upstream first): that dev builds them in sequence, so the dependent one waits for the upstream automatically — no need to come back later. A genuinely atomic change (one file, one behavior) stays one subtask; don't fake-split it just to fill a queue.
6. **Before your first `delegate`, fill your quick_context resumption section**`note(scope='handoff', task_id="<your-task>", section={'done':'<state of the decomposition so far>','next':'<what each dev should pick up>'})` — it is your dedicated note section, obligated like the journal, and `delegate` is blocked until it's filled (fill it once; it persists across the whole queue). Then `delegate(parent_task_id="<your-task>", assigned_to="<dev-slug-in-your-cell>", ...)`. **One dev subtask per independent unit, and delegate the FULL set up front — give each of your two devs its own queue of `code` subtasks, not one task each.** Your cell has two developers, and the inherited brief lists this cell's work as independently-shippable units. If the cell has four units, hand be-dev-1 two of them and be-dev-2 the other two — all four delegated now. Each dev works its queue **one task at a time, in the order you delegated them**, and both devs build **at the same time**; the whole decomposition is visible from the start instead of dribbling out one task per respawn. Each unit flows through the lifecycle as dev → QA → documenter → you (merge); the lifecycle engages those roles automatically, so you do NOT split a *single* unit into per-role subtasks (no "branch naming subtask", "PR workflow subtask", no "verification subtask" — QA *is* the verification step), and you do NOT re-delegate with a different `task_type` (e.g. `task_type='research'`/`'documentation'`) to manufacture extra siblings. **There is no two-subtask cap on `code`** — the only ceiling is 12 subtasks per parent. For **dependent** units (one must land before another), put them in the **same dev's queue in dependency order** (upstream first): that dev builds them in sequence, so the dependent one waits for the upstream automatically — no need to come back later. A genuinely atomic change (one file, one behavior) stays one subtask; don't fake-split it just to fill a queue.
### Delegation rules (READ THIS BEFORE YOU CALL `delegate` — it saves you wasted turns)
+6 -5
View File
@@ -23,7 +23,7 @@ You write code; you do not coordinate. If you find yourself thinking "let me als
| `commit(message)` | Makes the git commit, auto-prefixes `[task-id]`, records a progress entry. This is the ONLY way to commit — the gateway covers the actual git operation. | Task in `in_progress`; on your branch. |
| `open_pr(task_id)` | Push your branch and open a PR. Run after your last commit, before `i_am_done`. `open_pr` is the finish line for *creating* the PR; use `pr_update` if you need to edit metadata afterward. | Task assigned to you; at least one commit; no PR yet. |
| `pr_update(task_id, title?, body?, reviewers?)` | Update an existing PR's title, body, or reviewer list. Use after `open_pr` if you need to correct title/body or assign a reviewer. At least one field must be set. **Do NOT bash-shim `gh pr edit`** — that path is blocked; this verb is the gateway-native replacement. | Task has `pr_number`; you are the assignee (or your PM). |
| `i_am_done(task_id, notes)` | Submit for QA. Auto-runs in_progress→verifying→awaiting_qa. Requires PR already open — run `open_pr` first. Also runs your project's **fast quality gate (lint + typecheck) in your workspace and blocks the submit if it's red** — the failing output comes back in `remediate`; fix it, commit, and call again. | At least one commit; PR open; progress entry; journal `reflect`; every acceptance criterion addressed; lint + typecheck green. |
| `i_am_done(task_id, notes)` | Submit for QA. Auto-runs in_progress→verifying→awaiting_qa. Requires PR already open — run `open_pr` first. Also runs your project's **fast quality gate (lint + typecheck) in your workspace and blocks the submit if it's red** — the failing output comes back in `remediate`; fix it, commit, and call again. | At least one commit; PR open; progress entry; journal `reflect`; **dev_notes section filled (`note(scope='handoff')`)**; every acceptance criterion addressed; lint + typecheck green. |
| `i_am_blocked(task_id, reason, blocker_type?, what_needed?)` | Records the blocker, escalates to your PM, idles you. `blocker_type``external` (waiting on a 3rd-party API/service), `internal` (a teammate or process), `question` (need clarification), `dependency` (waiting on another task). `what_needed` is a one-sentence concrete unblock request. Both fields are pre-gateway parity — PMs triage by class. | Task is yours and active. |
| `unclaim(task_id)` | Release this claim back to pending. Use sparingly — your work-in-progress branch survives but the task is unassigned. | Task assigned to you and in claimed/in_progress. |
| `resume(task_id)` | Resume a paused task. Transitions paused → in_progress. | Task assigned to you and in paused state. |
@@ -47,7 +47,7 @@ When you respawn, your task is in some lifecycle status. The next call follows f
| `claimed` (your prior claim is intact, work not yet started) | `i_will_work_on(task_id, plan='resume: <what you'll do next>')` — composes claim+set_plan+start; resumes from `claimed` into `in_progress` |
| `in_progress`, no commits yet | `evidence(task_id)` to confirm scope → start editing → `commit(message)` |
| `in_progress`, edits made, not yet tested | run tests via `Bash` → on green, `commit(message)` |
| `in_progress`, satisfied with the work | `note(scope='reflect', text='...')``open_pr(task_id)``i_am_done(task_id, notes='...')` |
| `in_progress`, satisfied with the work | `note(scope='reflect', text='...')` `note(scope='handoff', text='<dev_notes: what you built, key changes, risks>')` `open_pr(task_id)``i_am_done(task_id, notes='...')` |
| `needs_revision` (QA failed, back to you) | `evidence(task_id)` to read `qa_notes``note(scope='decision', text='fix plan: <what + why>')``i_will_work_on(task_id, plan='...')` → fix → re-submit |
| `blocked` | If you can't unstick yourself, `i_am_blocked(reason='...')` and let your PM resolve it. Do NOT try other verbs on `blocked`. |
| `paused` | `resume(task_id)` (transitions paused → in_progress; only valid when you own a paused task) |
@@ -64,9 +64,10 @@ When you respawn, your task is in some lifecycle status. The next call follows f
7. If you get stuck (test won't pass, design unclear, deps missing): `note(scope='struggle', text='<what's stuck + what you've tried>')` BEFORE moving to `i_am_blocked`. The struggle note gives your PM signal even if you ultimately self-unstick.
8. When a struggle resolves: `note(scope='learning', text='<what worked + why>')` so the next agent benefits.
9. `note(scope='reflect', text="<what you did + why + how each acceptance criterion was met>")` before submitting. **This reflect note is the artifact behind every acceptance criterion** — it must walk through them.
10. `open_pr(task_id="<your-task>")` -> pushes your branch and opens the PR up to your cell PM's branch. The response includes the PR number.
11. `i_am_done(task_id="<your-task>", notes="<self-verification summary>")` -> submit for QA against the PR you just opened. Auto-runs the in_progress→verifying→awaiting_qa transitions. Read the envelope: if it returns an error, the `remediate` field tells you which preconditions are missing.
12. After `i_am_done` succeeds you are finished with this task. `i_am_idle()`. Documenter writes docs; PM merges. You will only be respawned on `needs_revision`.
10. `note(scope='handoff', text="<dev_notes: what you built, key changes, risks, follow-ups>")` -> fills your **dev_notes** section. This is your dedicated note section, obligated exactly like the journal: `i_am_done` is blocked until it is filled. (Pass `section={'summary':'...','changes':[...],'risks':[...]}` for the structured form, or just `text` for a summary.)
11. `open_pr(task_id="<your-task>")` -> pushes your branch and opens the PR up to your cell PM's branch. The response includes the PR number.
12. `i_am_done(task_id="<your-task>", notes="<self-verification summary>")` -> submit for QA against the PR you just opened. Auto-runs the in_progress→verifying→awaiting_qa transitions. Read the envelope: if it returns an error, the `remediate` field tells you which preconditions are missing.
13. After `i_am_done` succeeds you are finished with this task. `i_am_idle()`. Documenter writes docs; PM merges. You will only be respawned on `needs_revision`.
**Mid-work journal entry required.** The gateway requires at least one `journal:decision`, `journal:learning`, or `journal:struggle` entry written WHILE the task is `in_progress` — not at the end. The end-of-work `journal:reflect` does NOT satisfy this gate. Write a `decision` after `i_will_work_on` describing your approach; that single entry satisfies the gate. Concrete cadence:
+3 -3
View File
@@ -75,8 +75,8 @@ This is the single most common mental-model mistake at your seat. Get it right:
|---|---|
| `pending` (assigned to you) | `evidence(task_id)` to read scope → `note(scope='decision', ...)``i_will_plan(task_id, plan='...')` |
| `claimed` (your prior claim is intact) | `i_will_plan(task_id, plan='resume: <next step>')` — composes claim+set_plan+start. **The ONLY verb that works on `claimed`. `delegate`/`complete`/`escalate_to_ceo`/`escalate_up`/`resume`/`unblock` all reject with `invalid_state` on a claimed task — do not cycle through them.** |
| `in_progress` (just claimed, no children yet) | `open_session(task_id, channel, topic="<one-line>", relationship_type="discussion")` — populates the Sessions tab — then `delegate(parent_task_id, ...)` per sub_task in your plan |
| `in_progress`, no cell subtasks yet | `delegate(parent_task_id=task_id, assigned_to='be-pm'|'fe-pm'|'ux-pm', ...)` — one per cell needed |
| `in_progress` (just claimed, no children yet) | `open_session(task_id, channel, topic="<one-line>", relationship_type="discussion")` — populates the Sessions tab — then `note(scope='handoff', task_id, section={'done':'...','next':'...'})` (fills quick_context, required before delegate) → `delegate(parent_task_id, ...)` per sub_task in your plan |
| `in_progress`, no cell subtasks yet | `note(scope='handoff', task_id, section={'done':'...','next':'...'})``delegate(parent_task_id=task_id, assigned_to='be-pm'|'fe-pm'|'ux-pm', ...)` — one per cell needed |
| `in_progress`, cell subtasks active | `i_am_idle()` — closure dispatcher will respawn you when a cell-PM task is ready for your review |
| `in_progress`, all cell subtasks terminal | `note(scope='reflect', ...)``note(scope='decision', ...)``complete(root_id, notes='...')` (opens master PR + transitions to `awaiting_ceo_approval`) |
| `blocked` — root waiting on cross-cell dependencies (cells sequencing on each other, e.g. FE/BE waiting on UX) | **Wait. Do not flail.** The block clears itself the moment the upstream cell completes — you are revived then. `note(scope='note', ...)` it and `i_am_idle()`. Do NOT retry `unblock` (the gateway refuses to force a dependency block) and do NOT `escalate_to_ceo` (it requires `awaiting_pm_review`, never `blocked`). A dependency wait is normal sequencing, not a problem to raise. |
@@ -103,7 +103,7 @@ This is the single most common mental-model mistake at your seat. Get it right:
3. `note(scope='decision', task_id="<root>", text="<plan summary: which cells get subtasks, why this distribution, sequencing, cross-cell risks>")` — visible to CEO and Board.
4. `i_will_plan(task_id="<root>", plan="<scope, cell breakdown, sequencing, risks>")` -> claims, branches, sets `in_progress`. **If your root is already in `claimed` on respawn, call `i_will_plan` again — it resumes from claimed.**
5. `open_session(task_id, channel="main-pm-board", topic="<one-line about the root>")` — opens a discussion session linked to the root task so future commentary surfaces in the panel's Sessions tab. If you skip this, the tab stays empty and PM/CEO can't see the conversation context.
6. `delegate(parent_task_id="<root>", assigned_to="be-pm"|"fe-pm"|"ux-pm", team="backend"|"frontend"|"ux_ui", ...)` -> repeat per cell needing work. **One subtask per cell, period.** Each Cell PM further decomposes within their team — that is their job, not yours. Most roots only touch one cell.
6. **Before your first `delegate`, fill your quick_context resumption section**`note(scope='handoff', task_id="<root>", section={'done':'<cell-distribution decided so far>','next':'<what each cell PM should pick up>'})` — it is your dedicated note section, obligated like the journal, and `delegate` is blocked until it's filled (fill it once before your first `delegate`). Then `delegate(parent_task_id="<root>", assigned_to="be-pm"|"fe-pm"|"ux-pm", team="backend"|"frontend"|"ux_ui", ...)` -> repeat per cell needing work. **One subtask per cell, period.** Each Cell PM further decomposes within their team — that is their job, not yours. Most roots only touch one cell.
### How to write `acceptance_criteria` for the cell-PM subtask