| name | dispatcher-handover |
| description | To avoid continuing the Dispatcher session while its context stays bloated, write the monitoring state (active workers / latest polling cursor / pending escalations) to a handover file, then — on the Secretary's instruction — prepare a fresh Dispatcher session via /clear → /dispatcher-resume. Use when a DISPATCHER_HANDOVER peer message arrives from the Secretary, or when the Dispatcher itself judges that context has grown long.
|
| effort | low |
| allowed-tools | ["Read","Write","Edit","Bash(py -3 ../tools/journal_append.py:*)","Bash(bash ../tools/journal_append.sh:*)","Bash(python3 -c:*)","Bash(py -3 -c:*)","Bash(ls:*)","Bash(cp:*)","mcp__renga-peers__send_message"] |
dispatcher-handover: hand off the Dispatcher
Without dragging the Dispatcher session on, produce a handover file that
carries the current monitoring state and the Dispatcher's standing as an
org member into the next session. After writing, notify the Secretary
to "once you ack, send_keys /clear → /dispatcher-resume".
Transport layer — both systems (ORG_TRANSPORT: default renga / opt-in broker): this skill's mcp__renga-peers__* calls (the handover notification send_message etc.) are written for default renga and can be followed as-is when ORG_TRANSPORT is unset (default behavior unchanged). Under ORG_TRANSPORT=broker (opt-in, revertible), the fully qualified names get machine-substituted to mcp__renga-peers__* → mcp__org-broker__*, and the ack receive from the Secretary is also push-primary under broker (the per-pane channel sidecar server:org-broker-channel injects via notifications/claude/channel into the idle session; runtime push-first 0.1.24+, transport-lab docs/design/broker-native-roles.md §9). On push failure the fallback is an active check_messages (a nudge can be a trigger, but it does not wake an idle session, so an active poll is the canonical reception path — §9.6). The Secretary's /clear → /dispatcher-resume keystrokes use mcp__org-broker__send_keys in the same shape, and errors gain the broker-specific codes (see the broker section in .claude/skills/org-delegate/references/renga-error-codes.md). See the "Transport layer (transport) both systems" section of .dispatcher/CLAUDE.md and docs/contracts/backend-interface-contract.md Surface 8 (ratified 2026-06-14; the push-primary additive amendment S3 is ratified 2026-06-15, with existing ratified text unchanged) for details. The default-renga procedure is unchanged (broker is additive).
Key preconditions:
- This skill is run by the Dispatcher itself (cwd
.dispatcher/).
It is not invoked directly from the Secretary.
- Keep the Worker / Secretary / Curator panes alive.
/clear only resets
the Dispatcher Claude's context, so as long as state.db and the handover
file allow recovery, monitoring stays uninterrupted.
- Keep the Dispatcher pane (name=
dispatcher) alive too. Closing the pane
itself changes pane_id / peer_id and forces the /loop 3m hook to
be re-registered. The Secretary takes the canonical path of merely
sending /clear and /dispatcher-resume keystrokes via
mcp__renga-peers__send_keys(target="dispatcher", ...) so that the pane
is preserved.
- The state DB (
.state/state.db) is the single SoT. Pane / peer identity
is written into the handover as a reference value, but on resume the
ground truth is the live observation from list_panes / list_peers.
- To avoid creating a gap in the monitoring loop, the following files must
never be deleted or edited:
.state/dispatcher-event-cursor.txt (next cycle's poll_events cursor)
.state/dispatcher/worker-idle-state.json (idle streak for stall detection)
.state/dispatcher/curate-inflight.json (start record of an on-demand curate; only if present)
.state/pending_decisions.json (pending-decisions register)
.state/workers/worker-*.md (per-worker run state)
The handover file is restricted to the additional context above
(no human-conversation temperature, but in-flight dispatch context and
recent anomaly observations).
Step 1: collect what to hand over
Before writing, extract the following from the Dispatcher's (your) context:
- Recent dispatch context
- DELEGATE received → spawn success/failure, and task IDs that have moved
onto the escalation path
- Workers under monitoring
- Pane names whose
Status in .state/workers/worker-*.md is active,
plus the latest Progress Log excerpt
- Recent anomaly observations summary
- Out of the past cycle's
journal_append'd anomaly_observed /
notify_sent, the ones still unresolved
- Undelivered / failed sends
- Things escalated to the Secretary as
[pane_not_found] /
[split_refused] etc., or awaiting retry
- Next actions (Dispatcher's view)
- Workers to re-confirm next cycle, judgments waiting to be relayed
Step 2: pull structured info from state.db
Embed it in the handover as reference. Write to a sandbox-writable
$TMPDIR (falling back to /tmp if unset):
python3 -c "
from tools.state_db import connect
from tools.state_db.queries import get_org_state_summary
import json, os
conn = connect('.state/state.db')
out_path = os.path.join(os.environ.get('TMPDIR', '/tmp'), 'dispatcher-handover-state.json')
with open(out_path, 'w') as f:
json.dump(get_org_state_summary(conn), f, ensure_ascii=False, indent=2, default=str)
print(out_path)
"
From this, extract:
session.dispatcher_pane_id / session.dispatcher_peer_id (current identity)
active_runs[] (in-flight tasks)
active_worker_dirs[] (live worker directories)
- The most recent
recent_events — top ~5 of worker_spawned /
worker_reported / worker_escalation
The Dispatcher's cwd is .dispatcher/, so resolve relative paths one
level up:
python3 -c "
import sys, os
sys.path.insert(0, os.path.abspath('..'))
from tools.state_db import connect
from tools.state_db.queries import get_org_state_summary
import json
conn = connect('../.state/state.db')
out_path = os.path.join(os.environ.get('TMPDIR', '/tmp'), 'dispatcher-handover-state.json')
with open(out_path, 'w') as f:
json.dump(get_org_state_summary(conn), f, ensure_ascii=False, indent=2, default=str)
print(out_path)
"
Step 3: write the handover file
Destination: .state/dispatcher-handover.md (rooted at the repo root;
from the Dispatcher cwd .dispatcher/, that is
../.state/dispatcher-handover.md).
If a previous file exists, back it up to .prev.md before overwriting:
[ -f ../.state/dispatcher-handover.md ] && \
cp ../.state/dispatcher-handover.md ../.state/dispatcher-handover.prev.md
Format (YAML frontmatter + markdown):
---
created_at: <UTC ISO8601>
dispatcher_pane: <pane_id> / peer=<peer_id>
active_worker_count: <int>
event_cursor_present: <true | false>
idle_state_present: <true | false>
pending_decisions_count: <int>
---
# Dispatcher Handover
## Workers under monitoring
- worker-<task_id> (<worker_dir>): Status=<active|...>, one-line Progress Log excerpt
- ...
## Recent anomaly / notify_sent summary
- worker-<task_id>: kind=<approval_blocked|stall_suspected|relay_gap_suspected> ...
(If none, write "none" explicitly.)
## Undelivered / failed sends
- ...
(If none, write "none".)
## Next actions (Dispatcher's view)
- Re-confirm next cycle: worker-<task_id> due to <reason>
- ...
## Files to bridge the monitoring gap (read-only; this skill must not touch)
- `.state/dispatcher-event-cursor.txt`: next `poll_events` cursor (use as-is on resume)
- `.state/dispatcher/worker-idle-state.json`: idle streak for stall detection
- `.state/dispatcher/curate-inflight.json`: start record of an on-demand curate (only if present; after resume, Step 5.3 timeout management continues from its `started_at`)
- `.state/pending_decisions.json`: pending-decisions register
- `.state/workers/worker-*.md`: per-worker run state
## Reference: state.db snapshot
(Briefly transcribe session / active_runs / recent_events captured in Step 2.)
Writing notes:
- Write as "a memo to your next self", not as "past logs".
- Never write secrets / tokens / passwords.
- Assume the Secretary / human may also read this file.
Step 4: record the event
The Dispatcher cwd is .dispatcher/, so call one level up:
bash ../tools/journal_append.sh dispatcher_handover \
active_workers=<int> pending_decisions=<int> \
note=context_compaction
Step 5: notify the Secretary
Via mcp__renga-peers__send_message(to_id="secretary", message=...),
convey the following:
DISPATCHER_HANDOVER_READY: written to ../.state/dispatcher-handover.md.
Once you ack, please use mcp__renga-peers__send_keys(target="dispatcher")
to issue /clear and then /dispatcher-resume in order.
Do not close the pane (preserving pane_id keeps the monitoring gap minimal).
active workers: <count>, pending decisions: <count>.
The Secretary receives this message and — without escalating to the
human (a routine handover is not a decision request) — uses send_keys
to issue /clear and /dispatcher-resume. Once the Secretary's ack
returns, this skill is complete; do nothing further (the assumption is
that /clear will reset your context).
What the Dispatcher must NOT do:
- Issue
/clear itself (it is the recipient of an external send_keys)
- Send SHUTDOWN to Workers or the Curator (keep panes alive)
- Edit / delete
.state/dispatcher-event-cursor.txt /
worker-idle-state.json / curate-inflight.json / pending_decisions.json
(resume continuity breaks)
- Stop
/loop 3m itself (the design resumes it after resume; the current
cycle continues)