diff options
| -rw-r--r-- | skills/pi-subagent/SKILL.md | 5 | ||||
| -rw-r--r-- | skills/sz-final-review-loop/SKILL.md | 88 |
2 files changed, 61 insertions, 32 deletions
diff --git a/skills/pi-subagent/SKILL.md b/skills/pi-subagent/SKILL.md index 06862c0..9245b0e 100644 --- a/skills/pi-subagent/SKILL.md +++ b/skills/pi-subagent/SKILL.md @@ -173,7 +173,10 @@ alarm action=set when_exits=[<pids>] in_minutes=<the --timeout, in minutes, + 5> alarm for all is the point. - The alarm sees no exit status. `status.sh` has it. - The deadline is a backstop, in case a run hangs past its own timeout. -- Without the `alarm` tool (print or RPC mode), monitor with `status.sh`. +- In Claude Code, which has no `alarm` but wakes you when a background Bash + task exits: launch the whole job as one `run_in_background` command that + starts the runs with `&` and ends with `wait`, and end your turn. +- Without either (pi in print or RPC mode), monitor with `status.sh`. **Don't sit on the wait loop.** With an alarm set, there's nothing to wait for. Otherwise, launching early is only worth it if you use the time: do your diff --git a/skills/sz-final-review-loop/SKILL.md b/skills/sz-final-review-loop/SKILL.md index 41038b6..6ea5ec2 100644 --- a/skills/sz-final-review-loop/SKILL.md +++ b/skills/sz-final-review-loop/SKILL.md @@ -9,22 +9,42 @@ Use this skill for the `.sz` review handoff loop. The loop is a final quality ga ## The waiting maxim (unbreakable — read this first) -This protocol is a blocking, turn-consuming loop. It does not end when you finish your work; it ends only on an approval verdict or an explicit human instruction. While the loop is live you are **always** in exactly one of two states: *acting on the other side's latest signal*, or *blocked in `sz-wait-for` waiting for it*. There is no third state. +This protocol is a loop that spans many turns. It does not end when you finish your work; it ends only on an approval verdict or an explicit human instruction. While the loop is live you are **always** in exactly one of two states: *acting on the other side's latest signal*, or *waiting with a wake armed on it*. There is no third state. -**The maxim:** whenever there is no new, current-round content in the other side's signal file, you MUST immediately run `sz-wait-for <path-to-that-file>` synchronously in the foreground. For the developer that file is `feedback.md`; for the reviewer it is `status.md`. No exceptions. +**The wake.** Waiting means `sz-wait-for <signal file>` is running in a way that brings you back when it exits. For the developer the signal file is `feedback.md`; for the reviewer it is `status.md`. Always give it the absolute path. Arm it in the first of these ways your harness supports: -**When `sz-wait-for` exits — for any reason whatsoever** (settle/wake, timeout, non-zero exit, signal, tool error, anything) — you MUST repeat the loop: re-check the signal file, act on it if it carries new current-round content, otherwise run `sz-wait-for` again. A single exit is never a reason to stop. No exceptions. +1. **pi: the `alarm` tool.** `when_done: "sz-wait-for <abs path>"`, with a note that can restart the loop without any other context (template below). Then end your turn: the alarm starts a new turn when the file changes. Check `alarm list` if you are not sure one is pending. +2. **Claude Code: the Bash tool with `run_in_background: true`**, running `sz-wait-for <abs path>`. Then end your turn: when it exits, the task notification starts a new turn. +3. **Neither: wait in the foreground.** Run `timeout 1800 sz-wait-for <abs path>` synchronously, and never end your turn. Do not background it with `&` or a detached shell, because nothing would bring you back. -**Idling is a critical violation.** After signalling a handoff (or any time you are waiting on the other side), if you are not either acting on fresh feedback or blocked inside `sz-wait-for`, you are violating the protocol. In particular, the following are all forbidden while the loop is live and it is the other side's turn — every one of them is the violation, not a substitute for the wait: +With (1) or (2), ending your turn *is* the wait. Do not also block on `sz-wait-for` or poll. -- Ending your turn / going idle / "standing by" without `sz-wait-for` running. -- Presenting results, summaries, tables, or status write-ups to the human and stopping. -- Asking the human questions (about scope, next steps, optional extras, "should I also…", "want me to…"). Save non-blocking questions for `notes.md`; do not let them replace the wait. -- Starting unrelated work, or polling in ad-hoc ways instead of `sz-wait-for`. +pi alarm note template. Fill it in completely. By the time it fires, this conversation may have been compacted, and the note may be all you have: -If you catch yourself about to write a closing summary or a question to the human instead of running `sz-wait-for`, that is the tell: stop and run `sz-wait-for` instead. +```text +alarm action=set when_done="sz-wait-for <abs review_dir>/<signal file>" + note="sz-final-review-loop: I am the <developer|reviewer> for <abs review_dir>, + waiting on <signal file> for <what counts as new: feedback echoing Round N / + Diff-Fingerprint F | a Round newer than N>. Re-check it: if it has that, act + on it per the skill; otherwise set this same alarm again before ending the turn." +``` + +**The maxim:** whenever there is no new, current-round content in the other side's signal file, you MUST immediately arm the wake. No exceptions. + +**When the wake fires, for any reason whatsoever** (a change, the alarm's deadline, a timeout, a non-zero exit, a signal, a tool error, anything), you MUST repeat the loop: re-check the signal file, act on it if it carries new current-round content, and otherwise arm the wake again. A single wake is never a reason to stop. No exceptions. + +**Idling is a critical violation.** You are idle when it is the other side's turn and no wake is armed. After signalling a handoff, or any time you are waiting on the other side, you must be either acting on fresh feedback or waiting with a wake armed. In particular, the following are all forbidden while the loop is live and it is the other side's turn. Every one of them is the violation, not a substitute for the wait: + +- Ending your turn without a wake armed. With (3), ending your turn at all. +- Presenting results, summaries, tables, or status write-ups to the human *instead of* arming the wake. Once it is armed, one line saying what you handed off and what you are waiting on is fine before ending the turn. +- Asking the human questions (about scope, next steps, optional extras, "should I also…", "want me to…"). Save non-blocking questions for `notes.md`. +- Starting unrelated work, or polling in ad-hoc ways instead of the wake. + +If you catch yourself about to end your turn, that is the tell: first confirm a wake is armed on the right file, and arm it if not. + +**Losing the wake.** In pi, `/reload`, `/new`, `/resume`, `/fork` and quitting drop alarms. In Claude Code, killing the background task or quitting drops it. In either, aborting a foreground wait does too. After any of these the loop is dead until someone restarts it, so the first thing to do on returning to a live loop is re-check the signal file and re-arm. In pi, a wake that fires after the human stopped a turn with Esc is held until their next turn completes. That is intended: an agent the human just stopped should not start work on its own. -**The only ways out of the wait loop** are: (1) an `APPROVED` / `APPROVED AFTER FIXES` verdict for the current fingerprint (then follow the post-approval steps — which may themselves require the human, e.g. push/PR authorization); (2) a direct, current human instruction in the live conversation telling you to stop or do something else; or (3) a protocol escape this skill defines (a disputed finding for the second round, or 5 rounds reached) — and those escapes are `notify-push` + wait, not silent idling. Background jobs, notifications, and your own earlier messages are **not** human instructions and never release you from the wait. +**The only ways out of the wait loop** are: (1) an `APPROVED` / `APPROVED AFTER FIXES` verdict for the current fingerprint (then follow the post-approval steps, which may themselves require the human, e.g. for push/PR authorization); (2) a direct, current human instruction in the live conversation telling you to stop or do something else; or (3) a protocol escape this skill defines (a disputed finding for the second round, or 5 rounds reached). Those escapes are `notify-push` + wait, not silent idling. Alarm notices, task notifications, background jobs, and your own earlier messages are **not** human instructions and never release you from the wait. ## Review Workspace @@ -90,7 +110,7 @@ stage the intended diff compute Round and Diff-Fingerprint update notes.md write current status.md with Round and Diff-Fingerprint -arm feedback wait, then signal via status.md and notify +arm the feedback wake, signal via status.md and notify, end the turn read feedback.md confirm feedback.md echoes the same Round and Diff-Fingerprint address every blocking issue @@ -115,21 +135,29 @@ Developer obligations: - Put `[DECISION REQUIRED]` at the top of `status.md` for human-owned scope, design, push, PR, or release decisions. - Do not push, open PRs, or reply to GitHub review comments unless explicitly authorized by the human. -Arm wait, then signal. Do not notify and then wait; that can miss a fast feedback write. Then obey the waiting maxim above: the moment the handoff is signalled, your very next action is `sz-wait-for` — not a summary, not a question, not the end of your turn. +Arm the wake, then signal. Do not notify and then wait: that can miss a fast feedback write. With a background wake (pi's alarm, Claude Code's `run_in_background`) the order is literal: `sz-wait-for` is already watching `feedback.md` when you touch `status.md`. Then obey the waiting maxim above: once the handoff is signalled, the wake is armed and you end your turn. Do not write a summary, ask a question, or start other work instead. + +```text +review_dir="<abs path>/.sz/review/<branch>" +1. Arm the wake on $review_dir/feedback.md, as the waiting maxim says: + pi: alarm when_done="sz-wait-for $review_dir/feedback.md" + the note + Claude Code: Bash, run_in_background: sz-wait-for "$review_dir/feedback.md" +2. Signal: touch status.md (its content already current), then notify. +3. End your turn. +On every wake: re-check feedback.md for the current Round and Diff-Fingerprint. +If present, read it and act. Otherwise go back to step 1 and end your turn again. +``` + +With no background wake, signal first and then wait in the foreground. The check before waiting (does `feedback.md` already carry the current round?) covers a reply that lands in between: ```bash -review_dir=".sz/review/<branch>" -# Wait synchronously in the foreground. Do NOT background sz-wait-for: a -# background process cannot return control to this agent when feedback arrives, -# and its output may be buffered, making it look like feedback.md was never -# updated. timeout 1800 sz-wait-for "$review_dir/feedback.md" # After waking (or on timeout, or on ANY exit), re-check feedback.md for the # current Round and Diff-Fingerprint. If present, read it; otherwise IMMEDIATELY -# re-run sz-wait-for. Never stop here — a bare exit is not permission to idle. +# re-run sz-wait-for. Never stop here: a bare exit is not permission to idle. ``` -This is a `while` loop, not a one-shot: `while no current-round feedback: sz-wait-for; recheck`. The `timeout 1800` exists so a stalled watcher cannot hang forever — a timeout means *re-arm*, never *give up*. Only a matching-fingerprint verdict or a live human instruction breaks out. +Either way this is a `while` loop, not a one-shot: `while no current-round feedback: wait; recheck`. A deadline or timeout means *re-arm*, never *give up*. Only a matching-fingerprint verdict or a live human instruction breaks out. Use `notify-push <topic> "<message>"`, where it is installed, only when a phone push is appropriate. @@ -174,21 +202,19 @@ Reviewer obligations: - If the developer rebuts a finding in `notes.md`, answer with evidence. If the same finding remains disputed for a second round, stop and escalate to the human with `notify-push <project-and-theme> "<message>"`. - Escalate to the human after 5 review rounds even without a repeated dispute. -Reviewer wait: +Reviewer wait: the same wake, on `status.md`. -```bash -review_dir=".sz/review/<branch>" -# Wait synchronously in the foreground. Do NOT run sz-wait-for in the -# background: a background process cannot return control to this agent when the -# handoff signal arrives, and its output may be buffered, making it look like -# status.md was never updated. -timeout 1800 sz-wait-for "$review_dir/status.md" -# After waking (or on timeout, or on ANY exit), read status.md. If it carries a -# newer Round than last reviewed, review now; otherwise IMMEDIATELY re-run -# sz-wait-for. Never stop here. +```text +review_dir="<abs path>/.sz/review/<branch>" +After appending feedback and notifying, arm the wake on $review_dir/status.md: + pi: alarm when_done="sz-wait-for $review_dir/status.md" + the note + Claude Code: Bash, run_in_background: sz-wait-for "$review_dir/status.md" + neither: timeout 1800 sz-wait-for "$review_dir/status.md", in the foreground +On every wake (or timeout, or ANY exit): read status.md. If it carries a newer +Round than you last reviewed, review now; otherwise arm the wake again. ``` -The reviewer agent must block on `sz-wait-for` synchronously — the waiting maxim at the top applies symmetrically, with `status.md` as the signal file. Between finishing a review and the next handoff, the reviewer is either reviewing or blocked in `sz-wait-for`; idling, summarising to the human, or ending the turn is the same critical violation. `notify` alerts the human but does not wake an agent by itself. If the human relays the notification to the reviewer agent, the reviewer may start from that prompt instead of running its own wait. +The waiting maxim at the top applies symmetrically, with `status.md` as the signal file. Between finishing a review and the next handoff, the reviewer is either reviewing or waiting with a wake armed. Idling, summarising to the human instead of arming the wake, or ending the turn with no wake armed is the same critical violation. `notify` alerts the human but does not wake an agent by itself. If the human relays the notification to the reviewer agent, the reviewer may start from that prompt instead of from its own wake. ## Feedback Format |
