本文へ移動
cccskills
無料GitHub で公開

dispatcher-resume

/dispatcher-handover で書き出した handover ファイルを読み込み、 ディスパッチャーを新しい session で復帰させる。/clear 直後の最初のターンで使う。

state.db の dispatcher_pane_id / dispatcher_peer_id を atomic に更新し、 worker monitoring の /loop 3m を再開する。「ディスパッチャー復帰」「resume」「引き継ぎから再開」と secretary から指示された ときに使う。

/org-start ではない(ワーカー・窓口・キュレーターは生きている前提)。

インストール方法を見る

含まれるファイル(2)

  • SKILL.md33.8 KB
  • SKILL.md.in30.3 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

dispatcher-resume: ディスパッチャーの復帰

/dispatcher-handover で書き出した .state/dispatcher-handover.md を読み込み、 ディスパッチャーとして最低限の自覚(組織員としての立ち位置・進行中の派遣・監視 対象ワーカー)を復元し、/loop 3m の worker monitoring を再開する。

前提:

  • ワーカー / 窓口 / キュレーターのペインは前 session から生きたまま残っている。 新たに spawn しない(/org-start ではない)。
  • 自ペイン(name=dispatcher)も生きている。secretary が send_keys で /clear → /dispatcher-resume を打鍵した直後の状態。pane_id / peer_id は 変わっていないはずだが、必ず観測して state.db を atomic 更新する。
  • state DB (.state/state.db) はそのまま使う。
  • 監視 gap を埋める内部状態ファイル(.state/dispatcher-event-cursor.txt(backend session に束縛された poll_events cursor) / .state/dispatcher/worker-idle-state.json / .state/dispatcher/curate-inflight.json(存在時) / .state/pending_decisions.json)は 前 session から残っている。新規作成・初期化しない(既存値からそのまま継続)。
  • handover ファイルが存在しないか古すぎる場合は、/org-start を案内して停止する。

輸送層(transport)両系 — 既定 broker / opt-in renga: 本ファイル(および各スキル)の mcp__org-broker__* 呼び出しは 既定 broker(ORG_TRANSPORT 無設定)で書いてあり、そのまま従えばよい(既定挙動)。ORG_TRANSPORT=renga(opt-in・切戻し可)では MCP サーバー名が renga-peers になり、ツールの 完全修飾名が mcp__org-broker__* → mcp__renga-peers__* に機械置換される(引数形・セマンティクスは同一なので手順の論理は変わらない)。輸送依存で手順が変わる点だけ renga 併記する:

  • 受信モデル: 既定 broker は push 一次(各ペイン同居の channel sidecar server:org-broker-channel が broker キューを ~1 秒間隔で claim→notifications/claude/channel で idle セッションへ本文注入。pull = ナッジ + check_messages は sidecar 不在 / unhealthy / channel 非対応ペイン(codex pull-peer)/ claude.ai login 不在時のフォールバック層)。ORG_TRANSPORT=renga 時は dispatcher / worker メッセージが <channel source="renga-peers" …> として in-band で push される。
  • spawn 儀式: 既定 broker は --mcp-config <broker> 注入による Claude Code folder-trust プロンプトの画面判定による機械承認に加え、push 一次のため channel sidecar を --dangerously-load-development-channels server:org-broker-channel で load し dev-channel 承認プロンプトを画面判定で機械承認する(2 段承認)。ORG_TRANSPORT=renga 時は --dangerously-load-development-channels server:renga-peers の「Load development channel?」を画面判定で承認する 1 段。 画面判定 = inspect_pane → claude-org-runtime dispatcher spawn-prompt-step が返した 1 手だけを send_keys する反復(runtime 0.1.43+)。盲目 Enter は禁止(folder-trust の初期カーソルは「No, exit」で、Enter 一発はワーカーを終了させる)。手順は spawn-flow 3-3b。
  • エラー分岐: 既定 broker は shared codes(pane_not_found / last_pane / invalid-params)に加え broker 固有 [token_invalid] / [session_invalid] / [tool_not_authorized] / [no_backend](= adapter_unavailable)/ [nudge_failed] / [peer_not_found] / [name_taken] を返しうる(未知コードは default-branch で escalate)。ORG_TRANSPORT=renga 時は broker 固有コードは発生しない。

new_tab / focus_pane は broker surface に無い(意図的除外)。契約面の正本は docs/contracts/backend-interface-contract.md Surface 8 + push-primary amendment(broker push 一次が 既定の契約、pull は fallback として retain)。opt-in renga は削除せず常時有効な切戻しの安全装置として維持する。broker 実走(dogfood)は Epic #6 Issue G スコープで本ファイルの既定運用経路ではない(二フレーム注記(Refs #604): ここの「既定 broker」はコード既定(tools/transport.py: DEFAULT_TRANSPORT、生成面はこれで render)。運用既定は broker dogfood が Epic #6 Issue G まで未活性のため renga で、両者は指す対象が異なり矛盾しない。総説は root CLAUDE.md。)

Step 0 の前: 残存 loop 予約 / stale 再発火ガード(重複起動の早期遮断)

/dispatcher-resume は handover を 1 回だけ消費する one-shot である(Step 7 で .state/dispatcher-handover.md を .consumed.md に rename する)。だが Step 5 で起動する /loop 3m の予約が、過去のバグや手動操作で /dispatcher-resume 自身を反復対象に握って いると、監視サイクルのたびに本 skill が再発火する。この stale 再発火 / 重複起動 を Step 0 に入る前に遮断する(恒久対策の経緯は knowledge/raw/2026-06-19-dispatcher-resume-loop-recursion.md)。

  1. live / consumed の handover 状態を 存在ベースで判定する(now との時刻比較に 依存しない。cold-start vs resume の分岐が live .md のみを対象とする .dispatcher/CLAUDE.md の規約と揃える):
    python3 -c "
    import os
    md = '../.state/dispatcher-handover.md'
    cm = '../.state/dispatcher-handover.consumed.md'
    if os.path.exists(md):
        print('resume')            # 正規の resume: live handover あり
    elif os.path.exists(cm):
        print('already_consumed')  # 既に消費済み: 残存 loop / 重複起動の疑い
    else:
        print('no_handover')       # handover が一度も無い: 真の cold-start 候補
    "
    
  2. already_consumed(live .md なし・.consumed.md あり): live handover が無い resume 起動だが .consumed.md が残っている。これは「(i) 直前に成功した resume の残存 loop 予約による再発火 / 重複起動(組織は健全・監視ループ稼働中)」か「(ii) 組織が止まって いて本来 cold-start が要る状況での誤起動」のいずれか。存在判定だけで no-op に倒すと (ii) の cold-start 案内を恒久的に隠すので、監視対象が実際に live かを観測して分岐する:
    • mcp__org-broker__list_panes / mcp__org-broker__list_peers で 監視対象が live かを確認する: active な worker ペイン(role == "worker")が 1 つ以上ある、または .state/dispatcher/curate-inflight.json が存在する(= 監視ループが回っているべき状態)。 list_peers の直前に .claude/skills/org-delegate/references/capability-first-drive-operational-gate.md を Read し、monitoring-read-only の分岐を適用する(同 reference §6 の表 #5)。capability 形 かつ未承認なら列挙を live 判定に使わず破棄し、list_panes の role == "worker" と curate-inflight.json の有無だけで分岐する(停止しない・待ち時間 0 分)。 承認済み(同 reference §2 の first_drive が recorded)のときは §1-2 の三値判定を通し、 「在」と出たワーカーだけを live として数える — 他タブの別 org のワーカーを live と誤認すると (ii) の cold-start 経路が抑止される。「unknown」は live に数えないが、(ii) にも倒さない: 判定不能を「監視対象なし」と読み替えると誤った /org-start 案内で健全な組織を壊しうる (不可逆側)。終端処理は (i) と同じ(早期 exit + Step 5 の monitoring ディレクティブで /loop を再 arm し、残存予約を空のまま放置しない)とし、secretary には DISPATCHER_RESUME_INDETERMINATE: 監視対象の同タブ性を確定できず(unknown N 件)。 live 判定を保留して監視ループのみ再開しました。 を送って判断を仰ぐ。 unknown のワーカーは監視対象・active のまま残す(.state/workers/worker-*.md を Status: pane_closed にせず WORKER_PANE_EXITED も送らず .state/dispatcher/worker-idle-state.json の record も消さない)。再評価は再 arm した /loop 3m の通常サイクルが行う。 どの分岐にも落ちないまま skill を終えない(一度きりの skill が loop に再発火され続ける)。
    • (i) 監視対象が live = stale 再発火 / 重複起動: 組織は健全で cold-start 不要。 DISPATCHER_RESUME_FAILED を 送らず(誤った /org-start 案内を出さない)、 Step 1 以降に進まず早期 exit する。残存予約を空のまま放置しない: 監視 /loop が /dispatcher-resume を反復対象に握っている兆候があれば、Step 5 の monitoring 専用 ディレクティブ(INVARIANT(loop-prompt) 準拠の /loop 3m ...)で loop を明示的に再 arm して予約を上書きする(重複起動はしない=単一 loop に収束)。既に monitoring ディレクティブ で回っていれば当該サイクルは no-op heartbeat(何も出力しない)。どちらの分岐でも予約を skill 自身に握らせたまま放置しない。再発火の事実だけ journal に残す:
      bash ../tools/journal_append.sh anomaly_observed \
          source=dispatcher_resume worker=dispatcher kind=stale_loop_refire confidence=n/a \
          note=handover_already_consumed
      
    • (ii) 監視対象が無い = 本来 cold-start が要る誤起動: stale 再発火ではない。no-op に 倒さず Step 1 の「handover ファイルなし」分岐へフォールスルーし DISPATCHER_RESUME_FAILED → cold-start 案内を出す(cold-start 案内を隠さない)。
  3. resume(live .md あり): 通常どおり Step 0 へ進む。
  4. no_handover(live .md も .consumed.md も無し): 通常どおり Step 0 → Step 1 へ 進み、Step 1 の「handover ファイルなし」分岐で DISPATCHER_RESUME_FAILED → cold-start 案内に落ちる。

Step 0: 自分の identity を確認する

  1. mcp__org-broker__set_summary で「Dispatcher: 監視(resumed)」をセット

  2. caller pane id を確定する(focused: true は「そのタブで今フォーカスされているペイン」で あって caller 自身ではない。人間がフォーカスを移した瞬間、別ペインを dispatcher に改名し、 その id を dispatcher_pane_id として DB に焼き付けてしまう): 環境変数 RENGA_PANE_ID (echo "${RENGA_PANE_ID:-unset}")を起点に、mcp__org-broker__list_panes へ同一 id のレコードが 在ることを照合する。ここで確定した id が Step 2 で書く dispatcher_pane_id であり、以後の routing はこれを掴む。規則の正本は docs/contracts/backend-interface-contract.md T-§4.2 の caller pane id 取得規則

    • broker(ORG_TRANSPORT=broker)では RENGA_PANE_ID を読まず、最初から caller-id 未確定 に 倒す: broker には RENGA_PANE_ID に相当する caller pane id を out of band で供給する surface が 無いので、この取得規則は broker では常に未確定に落ちる。list_panes に数値 id のエントリが在って 手元で掴めていても例外にならない(数値 id は MUST の片方=相対セレクタでないことしか満たさず、 もう片方=自タブと確立済みの列挙から採った id でありその対象が caller であること、を満たさない)。 したがって broker では下の caller-id 未確定 分岐へそのまま進み、dispatcher_pane_id を渡さない
  3. 照合できたレコードの name/role を確認:

    • 期待値: name == "dispatcher" かつ role == "dispatcher"
    • 不一致なら mcp__org-broker__set_pane_identity(target="<RENGA_PANE_ID の値>", name="dispatcher", role="dispatcher") で修復(相対セレクタでは撃たない)
    • caller-id 未確定(RENGA_PANE_ID 未設定 / list_panes に同一 id 無し / broker 等で同等の caller-id を入手できない): 自己修復を実行せず、dispatcher_pane_id も渡さないまま (Step 2 の update_session() は未指定を「保持」と解釈するので既存値が温存され、これ自体が fail-closed になる)Step 1 へ進み、identity 未確認であることを Step 6 のブリーフィングで secretary に明示して続行判断を仰ぐ(target="focused" や裸 name へフォールバックしない)
  4. mcp__org-broker__list_peers で name == "dispatcher" の peer_id を取得。 呼び出しの直前に .claude/skills/org-delegate/references/capability-first-drive-operational-gate.md を Read し、monitoring-read-only の分岐を適用する(同 reference §6 の表 #4)。capability 形 かつ未承認なら列挙から peer_id を採らず破棄し、2 で確定した caller pane id で identity を 確定して進む(停止しない・待ち時間 0 分)。 このとき Step 2 の DB 書き込みでは dispatcher_peer_id を渡さない(update_session() は None / 未指定を「保持」と解釈する契約なので、既存値がそのまま残る)。placeholder や 観測できなかった値を書くと、以後の routing が壊れた id を掴む。dispatcher_pane_id は 2 で確定した caller pane id をそのまま書く(caller-id 未確定 のときは渡さない)。Step 6 のブリーフィングでは peer=<未取得: capability gate 縮退中> と明示して secretary に伝える。

    capability 形かつ承認済み(同 reference §2 の first_drive が recorded)のときも、自分の peer_id は名前引きで確定しない(§1-2-d)。mcp__org-broker__list_peers は caller を除外するので、 name == "dispatcher" に一致したレコードは同タブに 1 件だけ在っても自分ではありえず、 他タブのみ / 同タブ性 unknown / same_tab=True が複数の各分岐と合わせて、名前引きの結果が 何であれ peer_id は未確定のまま先へ進む。したがって Step 2 の DB 書き込みでは dispatcher_peer_id を渡さない(update_session() の「未指定 = 保持」で既存値を温存する。 生きた同一ペインを引き継ぐ resume では保持が正しく、渡さないこと自体が fail-closed になる)。 更新するのは 2 で確定した caller pane id(dispatcher_pane_id)だけである。Step 6 の ブリーフィングでは peer=<未取得: 名前引きでは自 peer を同定できない> と明示して secretary に伝える。

Step 1: handover ファイルを読み込む

ディスパッチャーの cwd は .dispatcher/ なので、リポジトリ root のパスを 1 階層上に解決する。

  1. .state/dispatcher-handover.md が存在するか確認:
    ls -la ../.state/dispatcher-handover.md 2>&1
    
    • 存在しない → secretary に通知して停止:
      DISPATCHER_RESUME_FAILED: handover ファイルがありません。
      /org-start でディスパッチャーを cold start してください。
      
  2. フロントマター created_at を見て鮮度を判定する。created_at は決定的 UTC で書かれている (/dispatcher-handover) ので、比較用の now も決定的 UTC で取得する (date -u +%Y-%m-%dT%H:%M:%SZ、PowerShell 環境は (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))。local(JST)時刻で now を 取ると now - created_at が約 9 時間ぶれ、24h / 7d 境界付近で鮮度を誤判定するため:
    • 24 時間以内 → そのまま採用
    • 24 時間超〜7 日以内 → secretary に警告(「handover が古い、続行する旨」)
    • 7 日超 → 採用せず /org-start への切り替えを推奨し停止
  3. ファイル本文を Read で取り込む。書かれている内容は次 session の自分にとっての 「事実」として扱う(後の Step 3 で state.db と照合する)。

Step 2: state.db の dispatcher identity を atomic 更新する

Step 0 で観測した pane_id / peer_id を StateWriter.transaction() 経由で 1 トランザクションで 書く(post-commit hook が .state/org-state.md を再生成 してくれる)。これが acceptance の「state.db identity が atomic 更新」要件の本体。

python3 -c "
import sys, os
sys.path.insert(0, os.path.abspath('..'))
from pathlib import Path
from tools.state_db import connect
from tools.state_db.writer import StateWriter
conn = connect('../.state/state.db')
with StateWriter(conn, claude_org_root=Path('..')).transaction() as w:
    w.update_session(
        dispatcher_pane_id='<observed_pane_id>',
        dispatcher_peer_id='<observed_peer_id>',
    )
"

Step 0 で peer_id が未確定だった場合(capability gate の縮退中、または承認済み路で名前引きから 自 peer を同定できなかった場合)は、dispatcher_peer_id を渡さない形で呼ぶ。上の例をそのまま 使うと観測していない値を書き込むことになる:

python3 -c "
import sys, os
sys.path.insert(0, os.path.abspath('..'))
from pathlib import Path
from tools.state_db import connect
from tools.state_db.writer import StateWriter
conn = connect('../.state/state.db')
with StateWriter(conn, claude_org_root=Path('..')).transaction() as w:
    w.update_session(
        dispatcher_pane_id='<observed_pane_id>',
    )
"

Step 0 が caller-id 未確定 に落ちていた場合は、同じ理由で dispatcher_pane_id も渡さない (両方とも未確定で update_session() に渡す引数が残らないなら、この Step 2 自体を skip する)。 focused から採った id で埋めてはならない — 人間のフォーカス位置に依存した別ペインの id を、 以後の routing の宛先として恒久的に焼き付けることになる。

update_session() は未指定を「保持」と解釈する契約なので、既存値がそのまま残る(生きた同一ペインを 引き継ぐ resume ではこれが正しい。詳細は Step 0 手順 3 / 手順 4 と共有 reference §1-2-d)。

  • dispatcher_pane_id / dispatcher_peer_id は 文字列で書く(schema は TEXT、 既存 /org-start も文字列を入れているので型を揃える)
  • transaction() 内なので片方だけ書いて失敗しても DB は半端な状態にならない
  • 観測値が handover frontmatter と異なっても、現観測(list_panes / list_peers)を 真値として優先する。差分があった旨を secretary 宛 message に含める

Step 3: state.db で現状を再取得し handover と照合する

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')
print(json.dumps(get_org_state_summary(conn), ensure_ascii=False, indent=2, default=str))
"

確認項目:

  • active_runs[] が handover の「監視対象のワーカー」セクションと整合するか
  • active_worker_dirs[] のワーカーディレクトリ存在

handover には書かれていないが state.db に active で残っている worker、または handover には書かれているが state.db / list_panes で消えている worker があれば、 secretary に 報告して 判断を仰ぐ(勝手に再 spawn / status 変更しない)。

Step 4: ペイン生存確認

mcp__org-broker__list_peers を再度呼び、handover に記載のワーカー名が現存するか 確認する。消えていれば secretary に WORKER_PANE_EXITED: worker-{task_id} (resume 時点で不存在) を通知(reconcile は窓口の責務)。

list_peers の直前に .claude/skills/org-delegate/references/capability-first-drive-operational-gate.md を Read し、monitoring-read-only の分岐を適用する(同 reference §6 の表 #6)。capability 形かつ 未承認なら列挙を不存在の根拠にせず破棄し、mcp__org-broker__list_panes と events テーブルの報告痕跡で判定する。 確定できなければ WORKER_PANE_EXITED を送らない(縮退中の「列挙に居ない」は死亡の証拠ではなく、 別 org の同名ピアと取り違えうる。同 reference §3-B-1)。停止しない・待ち時間 0 分。

capability 形かつ承認済み(同 reference §2 の first_drive が recorded)のときは、§1-2 の三値判定を handover 記載の各ワーカー名に適用する。「在」は生存として扱う。「不在」だけでは WORKER_PANE_EXITED を 送らず、送信可否は §1-2-c の pane 面裏取りが取れたかに従う。「unknown」でも送らず、indeterminate として secretary に報告する。(判定条件・三値の定義・評価順の正本は §1-2。ここに重ねて書かない) unknown / indeterminate のワーカーは監視対象・active のまま残し、Step 5 で再開する /loop 3m の 通常サイクルが再評価する。

Step 5: 監視ループの再開

以下をこの順序で評価する:

  1. inflight 再生成(先に実行): Step 4 の list_peers / list_panes に name == "curator" のペインが生きているのに .state/dispatcher/curate-inflight.json が無い場合(前 session が spawn 直後の inflight 書き込み前に途切れた等)、untracked curator を放置しないよう started_at = <決定的 UTC> / pane_id = <下記の pane id(backend が返した型のまま)> / reasons: [] / extended: false / curate_result: null / last_inspect_hash: null / last_inspect_ts: null で inflight を再生成する(フィールドの正本は .dispatcher/references/pane-close.md 5-3 の JSON。trigger_task_id は inflight を失った前 session の CLOSE_PANE 対象を指すフィールドで resume 側に値の出所が無いため書かない — Step 5.3 の完了受領 / timeout 判定はこの フィールドを読まない。curate_result は受領した CURATE_* を次サイクルへ持ち越す フィールドで、resume 時点では何も受領していないので初期値 null を明示して書く — Step 5.3 (a) が close できないまま inflight を保持するときだけ "done" / "skipped" / "error" に更新される)。 started_at は date -u +%Y-%m-%dT%H:%M:%SZ(PowerShell 環境は (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))の出力をそのまま埋め、 手書きの local(JST)時刻を Z で書かない(再生成 started_at が未来時刻になると Step 5.3 の now - started_at が負値となり curator が永久に孤立する。決定的取得の正本は同 5-3)。 pane_id は生存確認に使った mcp__org-broker__list_panes の列挙で name == "curator" かつ role == "curator" を指しているレコードの id を、mcp__org-broker__list_panes が返した JSON の型を 変えずに書く(列挙が手元にあるのでその場で採れる)。tmux backend は "%3" のような文字列、 WezTerm backend は整数を返すので、引用符の有無を型に合わせる — 文字列を引用符無しで 書くと JSON が構文非妥当になり、Step 5.3 も次の resume もこのファイルを読めず curator の 追跡が失われる(正本は同 5-3 の注記)。pane_id を欠いた形で再生成しない — Step 5.3 (a)/(b) の curator close はこの pane_id を identity 照合の起点にするので、欠けると schema 追加前の 旧形式ファイルと同じ扱いになり、close が列挙引き直しの fallback 経路に落ちる (.dispatcher/references/worker-monitoring.md Step 5.3)。 list_peers にのみ curator 名があり mcp__org-broker__list_panes の列挙に該当レコードが無い場合は 再生成せず secretary に informational として報告する(数値 pane id を採れないうえ、 messaging 面の名前一致は同タブの pane 生存の根拠にならない。Step 4 と同じ規律で、 契約 T-§4.2 が pane 制御可能性の推論を禁じている)。 以降の判定はこの再生成後の状態で行う(= このケースは必ず 2 の再開条件を満たす)
  2. /loop 3m 再開条件: handover の active_worker_count > 0、state.db の active worker dirs が非空、または curate-inflight.json が存在する (1 の再生成分を含む。オンデマンド curate の完了監視が引き継ぎ対象。 .dispatcher/references/worker-monitoring.md Step 5.3)のいずれかを満たせば 下記の monitoring 専用ディレクティブを渡して /loop 3m で worker monitoring を 再開する(prompt を省略しない)。この再開は「/loop で監視を再開します」と 宣言するだけでは武装されない — 宣言はターン終了と同時に失効するため、必ず 本ターン内で /loop を実 invoke すること(窓口側も inspect_pane で実行痕跡を 裏取りし、無ければ send_keys で再点火する運用である):
<!-- INVARIANT(loop-prompt): `/loop` の prompt 引数に skill 自身(`/dispatcher-resume`)や 他のスラッシュコマンドを渡さない。skill 実行ターン内で prompt を省略して `/loop` を 起動すると、反復対象としてアクティブな slash command が捕捉され、本 skill が 3 分ごとに 自己再帰する(2026-06-19 incident。詳細は knowledge/raw/2026-06-19-dispatcher-resume-loop-recursion.md)。必ず monitoring 専用の 自然文ディレクティブを明示的に渡すこと。tests/test_dispatcher_resume_loop_invariant.py が この不変条件を pin する。 -->
/loop 3m references/worker-monitoring.md(ディスパッチャー cwd .dispatcher/ 基準)の「監視ループ 1 サイクル」を 1 回だけ実行する(poll_events → check_messages → list_panes → inspect_pane → stall / relay-gap / pane_output 評価)。anomaly / stall / relay-gap / pane_exited を検出したサイクルのみ secretary へ通知し、検出が無ければ何も出力しない(毎サイクルの状況サマリや自然言語の状況描写を書かない)。cadence は 3 分以上を保ち短縮しない。スラッシュコマンドや本 skill を反復対象にしない。
  • 監視ループの 1 サイクル目で mcp__org-broker__poll_events は .state/dispatcher-event-cursor.txt の前 cursor(前 session 終了時点)から resume する。これで「pane が閉じている間に来た pane_exited は次回 poll で必ず拾える」 semantics が維持される(cursor 仕様)。ただし resume するのは cursor に記録された session_key が現 backend session と一致したときだけで、一致しなければ 1 サイクル目が cursor を破棄して「今以降」から張り直し、窓口へ EVENT_CURSOR_RESET を 1 行報告する (/clear を挟む間に renga / broker daemon が再起動していた場合がこれ。判定と手当ての 正本は .dispatcher/references/worker-monitoring.md 「監視ループ 1 サイクル」Step 1)。本 skill は cursor ファイルを読まず・書かず・消さない — 束縛の照合は監視ループ側の責務で、resume 側で先回りして初期化してはならない
  • mcp__org-broker__check_messages の 1 サイクル目で前 session 中にキューに溜まった worker → dispatcher peer message を drain する(broker = mcp__org-broker__check_messages。 broker は push 一次に再設計済だが、/clear 中に channel sidecar 経由で注入できなかった 滞留分はキューに残るため、resume 1 サイクル目の check_messages フォールバック drain で 取りこぼさず回収する=ツール名のみ変わり drain 論理は同型。§9.6 / §9.3 lease-reap)
  • .state/dispatcher/worker-idle-state.json は前 session の idle_streak_cycles を 保持しているので stall 検出の連続性も維持される

監視対象が 0 件(active worker dir も 0、active_runs も 0、curate-inflight.json も 無し、かつ 1 の評価後なので list_panes に curator ペインも不在)の場合のみ /loop を 始動せず、idle 状態を secretary に通知して待機する:

DISPATCHER_RESUMED_IDLE: 監視対象なしで resume 完了。DELEGATE 待機。

Step 6: secretary にブリーフィングを返す

handover + state.db の現状を統合した上で、secretary に簡潔に報告:

DISPATCHER_RESUMED: ディスパッチャー復帰完了。
- pane=<observed_pane_id> / peer=<observed_peer_id> (state.db 更新済)
- 監視対象ワーカー: <task_id list>
- pending decisions: <count>
- handover との差分: <あれば 1 行、無ければ「なし」>
- 監視ループ: /loop 3m 再開 (or idle)
  • Step 0 が caller-id 未確定 に落ちていた場合は pane=<未確定: caller pane id を同定できない> と 書き、(state.db 更新済) は付けない(前値保持のままであることを secretary に伝える)

Step 7: handover ファイルを consumed 状態に切り替える

resume が成功したら、.state/dispatcher-handover.md を .state/dispatcher-handover.consumed.md に rename する。これにより:

  • .dispatcher/CLAUDE.md 起動時の自動分岐(handover ファイルが直近 7 日以内に存在すれば resume)が「次の /org-start cold-start 時にも誤って resume に分岐する」事故を防ぐ
  • 直近 1 件のみ参照用に .consumed.md 形式で残る(次の /dispatcher-handover が新たに .md を書いた時点で .prev.md バックアップに置き換わる、または上書きされる)
mv ../.state/dispatcher-handover.md ../.state/dispatcher-handover.consumed.md
  • 既に .consumed.md があれば上書きで構わない(直近 1 件のみ保持)
  • .state/dispatcher-handover.prev.md は前回の /dispatcher-handover で書かれたバックアップ。読み込み済みでも消さない

イベント記録

ディスパッチャーの cwd は .dispatcher/ なので 1 階層上を呼ぶ:

bash ../tools/journal_append.sh dispatcher_resumed \
    pane_id=<observed_pane_id> peer_id=<observed_peer_id> \
    active_workers=<count> note=resumed_from_handover

やってはいけないこと

  • 新規にディスパッチャー / キュレーターを spawn する(既に生きている)
  • ワーカーに勝手に SUSPEND / SHUTDOWN を送る
  • .state/dispatcher-event-cursor.txt / worker-idle-state.json / curate-inflight.json / pending_decisions.json を初期化 / 削除する(前 session からの監視連続性が壊れる)
  • handover の内容と state.db の現状が食い違うときに、勝手にどちらかへ寄せる (必ず secretary に報告して判断を仰ぐ)
  • atomic 更新を分割して書く(必ず StateWriter.transaction() 1 ブロックで完結させる)
  • Step 5 の /loop 3m を prompt 省略で起動する / /dispatcher-resume(本 skill 自身)や 他のスラッシュコマンドを /loop の反復対象に渡す(skill が 3 分ごとに自己再帰する。 必ず monitoring 専用ディレクティブを明示的に渡す。Step 5 の INVARIANT(loop-prompt) 参照)

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

dispatcher-handover

無料日本語概要

ディスパッチャーのコンテキストを圧迫したまま session を続けるのを避けるため、 monitoring 状態(active workers / 直近 polling cursor / pending escalations)を handover ファイルに書き出し、secretary の指示で /clear → /dispatcher-resume の 流れで新しいディスパッチャー session を開始する準備をする。 Secretary から DISPATCHER_HANDOVER peer message を受領したとき、または ディスパッチャー自身が context が長くなったと判断したときに使う。

suisya-systems/claude-org-ja52026年10月12日 更新

goal-setup

無料日本語概要

プロジェクトのゴール台帳(registry/goals/<owner>/<repo>.md)を人間と対話して新規作成・改訂する。 README と open Issue からゴール候補を推定して提示し、「何を目指すか」「何が起きていたら未達か」を 短く質問して条項を固め、書式検証(tools/work_discovery_goals.py validate)を通してから保存する。 「ゴール台帳を書きたい」「ゴールを設定して」「ゴール未設定と出た」「台帳エラーを直して」 「このプロジェクトの目標を決めたい」等や、/work-discovery の「ゴール未設定」「ゴール台帳エラー」案内を 受けて窓口が起動する。候補の提示そのものは /work-discovery の役目で本スキルではない。

suisya-systems/claude-org-ja52026年10月12日 更新

org-attach

無料日本語概要

組織の生きているペイン(secretary / dispatcher / worker)へ tmux で**直接入る** ための **コマンドを出力するだけ** の read-only スキル。`mcp__org-broker__list_panes`(論理ペイン) と `/usr/bin/tmux -L claude-org-broker list-panes -a`(pane_id ↔ session マッピング)を pane_id(%N)で突き合わせ、各ペインに role + name(task_id) ラベル付きの attach コマンドを 生成する(読取専用 `-r` / 書込は `-r` 無し / デタッチは `Ctrl-b d`)。 「ワーカーのペインを見たい」「ワーカーのペインに入りたい」「dispatcher の様子を直接見たい」 「ペインに入りたい」「あのペインを直接覗きたい」「attach コマンド教えて」 「tmux でつなぎたい」「worker の画面に入る」等で発動。 自分で attach はせず・ペインも一切変更しない(コマンド文字列とペイン一覧表を表示するのみ)。 作業委譲(org-delegate)・ダッシュボードで状況一覧(org-dashboard)・watcher 停止(org-attention-stop) には発動しない。

suisya-systems/claude-org-ja52026年10月12日 更新

org-attention-start

無料日本語概要

attention notification watcher(承認待ち / 判断待ち / CI 失敗等を OS 通知 + 音で能動通知)を dispatcher ペインの右側に split で常駐起動する。`.state/attention.json` が未配置なら ja 既定テンプレートを `tools/templates/attention.example.json` から自動コピーする。 起動後のペイン id は `.state/attention_pane.json` に記録し、`/org-attention-stop` から参照する。 「attention 起動」「通知監視を始めて」「watcher を立てて」等で発動。 `/org-start` からの auto-start はしない(明示起動推奨ポリシー)。

suisya-systems/claude-org-ja52026年10月12日 更新

org-attention-stop

無料日本語概要

`/org-attention-start` で起動した attention watcher ペインを停止する。 `.state/attention_pane.json` に記録された pane_id を `list_panes` の name/role で identity 確認し、いまも attention watcher を指している場合だけ `close_pane`(pane 破棄)で 破棄する(pane_id が別ペインへ再割当て済みなら close せず stale sidecar として削除)。 「attention 止めて」「通知監視を停止」「watcher 落として」等で発動。

suisya-systems/claude-org-ja52026年10月12日 更新

org-conveyor

無料日本語概要

窓口が人間から「承認スコープの輪郭」を受けて、その内側で triage → worker 派遣 → iteration → verify → push → PR 作成 → CI 監視 を完了駆動で自走し、PR ごとに merge gate で必ず停止するベルトコンベア。/work-discovery + /org-delegate + verify + /org-pull-request + /org-escalation を呼ぶ薄い orchestrator。 発動条件: 人間が「この範囲は自走してよい」というスコープ承認を明示し、複数候補を 完了駆動で順次流したいとき(例「triage 上位の S 級バグ修正を空き pane 分まで自走、 merge は都度わたしが判断」)。起動主体は窓口に限定。スコープ外候補・判断境界・退出条件に 触れたら必ず halt する。merge 自動化はしない。

suisya-systems/claude-org-ja52026年10月12日 更新

suisya-systems のスキルをすべて見る

このスキルの問題を報告する