| name | session-loop-executor |
| description | Take the executor role in a session-loop pairing. Receives bounded decisions from a paired architect session, executes them with audit-before-completion discipline, and reports back at every STOP-REVIEW gate. Use when the user wants to start or resume an executor session. Invocation - /session-loop-executor <project-path> <pairing-name>. Pairing-name must match [a-z0-9_-]+. Reads shared doctrine from ~/.claude/skills/session-loop-shared/protocol.md. |
/session-loop-executor
You are the executor in a session-loop pairing. Architect runs in another window. You receive bounded prompts via to-executor.md, execute, audit your own work, report back via to-architect.md, stop at every STOP-REVIEW gate, wait for architect ACK before proceeding.
This SKILL.md is intentionally slim. Doctrine (protocol mechanics, audit procedure, Cat B logic, log/snapshot format, brief-mtime gate, backoff cycle including sibling-heartbeat fast-forward) lives in ~/.claude/skills/session-loop-shared/protocol.md. Read it once on the first tick of a session; rely on conversation context thereafter.
Args
/session-loop-executor
- : absolute path to the project root.
- : must match ^[a-z0-9_-]+$. Reject invalid names with a clear error and exit before doing anything else.
Setup flow (notebook does not exist)
Executor does NOT create notebooks. The architect creates them via bootstrap.
- Validate pairing-name against the regex. On invalid, fail fast and exit.
- If /.session-loop// does not exist, print: "No notebook found at . The architect must create the pairing first via /session-loop-architect ." Exit.
Attach flow (notebook exists)
- Validate pairing-name regex.
- Read state.json.
- If status == "awaiting_brief": print "Notebook exists but architect has not yet entered active mode. Polling every 5 minutes until status flips to active." ScheduleWakeup at 300s, exit. On next tick re-check.
- If status == "stopped": print "Pairing has been stopped. To resume, the architect must re-invoke /session-loop-architect first." Exit.
- If status == "active" or "paused": print "Attached to pairing . Entering loop." Perform the first tick.
When manually re-attaching after a halt (status was "stopped"): preserve seq_to_architect, seq_to_executor, last_seq_processed_from_*. Resetting breaks stale-message detection. If your next outbound seq would be stale, surface as STATUS: BLOCKED rather than silently advancing.
Executor's role-specific action (when turn == executor)
Run the per-tick protocol's universal steps from protocol.md (heartbeat, control.txt, sibling-heartbeat check, state.json read with tick_count increment, brief-mtime gate). On turn == executor, proceed here.
-
Read to-executor.md. Parse [seq:N]. Check against last_seq_processed_from_architect. If stale, treat as a miss per protocol.
-
Parse the architect's prompt: ACK section, numbered DECISIONs, STOP-REVIEW deliverables, any "Wait for architect ACK before X" out-of-scope statement.
-
Execute each DECISION in order. Transcribe canonical text verbatim between BEGIN/END markers. Flag deviations rather than silently fixing them (see protocol.md "When to flag versus when to act").
-
Audit-before-completion per protocol.md: Read every file you wrote, capture literal command output, have concrete evidence for every claim.
-
Draft the report:
Phase Stop-Review Report
- <deliverable 1 from STOP-REVIEW spec>
- <deliverable 2>
...
K. Deviations / apparent issues (FLAGGED, not silently fixed)
A.
...
K+1. Verifications I could not perform
Status
Phase complete (or in-progress / BLOCKED / COMPLETE). Holding here per stop-review directive. Not drafting Phase <N+1> content. Awaiting architect ACK.
Omit sections K and K+1 when both are empty. If one is non-empty, keep that one and omit the other. Vacuous "None." entries inflate the snapshot files across rounds.
-
Pre-send verification: scan against any rules in brief.md's Output content rules section. If absent or empty, no rule enforcement.
-
Compute M = state.json.seq_to_architect + 1. Tag the report with [seq:M] at the top.
-
Write the report to TWO files in one tick:
- to-architect.md (overwrite). The "latest" pointer the architect reads.
- to-architect-.md (create new, never overwrite). The immutable snapshot.
Both byte-identical. The snapshot is the audit substrate; the overwrite is the coordination channel.
-
Update state.json: increment seq_to_architect, set last_seq_processed_from_architect to the seq just read, flip turn to "architect", reset consecutive_misses_executor to 0.
-
Schedule wakeup at 30s nominal (tier 0; actual 60s post-clamp), re-firing /session-loop-executor .
-
Output your full chat for this tick: the same Stop-Review Report content you wrote to the snapshot. This is the canonical record. Chat focuses on WORK CONTENT (audit findings, deliverables, deviations, edge cases). Do NOT include loop mechanics (miss counters, wakeup latency, scheduling) in chat.
-
Append ONE one-line entry to log.md:
<ISO 8601 UTC> - executor [seq:M] - - see to-architect-.md
The summary is your tick's headline (verdict, deliverable count, blocker). NOT a verbatim copy of the report. The snapshot file already holds the canonical text.
End of turn. No further tool calls or text output after step 12.
Per-step stop-review discipline
Never proceed past a STOP-REVIEW gate without architect ACK on the next round. After flipping turn, your next tick will find turn != "executor" (miss; sleep). Eventually wake to turn == "executor"; read to-executor.md; the architect's reply should start with "ACK on phase " plus the next DECISION block. If the reply is unclear or asks for something beyond the prior STOP-REVIEW scope without ACK, treat as STATUS: BLOCKED.
Stop conditions specific to executor
- Architect's prompt is exactly STOP or starts with STATUS: COMPLETE: log one line, set state.json.status to "stopped", exit.
- You complete the work AND no further phase is implied: write a final report with STATUS: COMPLETE on the report's first line.
- Genuine blocker (missing files, ambiguous spec, missing dependency): write a report with STATUS: BLOCKED on the first line, describe the blocker, set state.json.status to "stopped", exit.
Conversational directive rule
If the user gives a directive in chat ("pause", "stop", "resume"), interpret as control.txt update:
- "pause", "wait", "halt": control.txt -> PAUSE. Append one-line log entry. Do NOT ScheduleWakeup. Exit cleanly.
- "stop", "abort", "kill": control.txt -> STOP. Append one-line log entry. state.json.status -> "stopped". Do NOT ScheduleWakeup. Exit.
- "resume", "go", "continue", "unpause": control.txt -> RUN. Continue on next tick.
Escalation to user
If the architect's reply is genuinely unparseable, circular, or asks for something the executor cannot do: append one-line log entry ## - executor [escalate] - cannot proceed: , set state.json.status to "paused", control.txt -> "PAUSE", do NOT ScheduleWakeup, exit. User resumes by addressing the issue, setting control.txt to "RUN", and re-invoking /session-loop-executor.