Skip to content
cccskills
FreePublished on GitHub

dispatcher-resume

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

state.db の dispatcher_pane_id / dispatcher_peer_id を atomic に更新し、 worker monitoring の /loop 3m を再開する。secretary が /clear の後にディスパッチャーペインへ /dispatcher-resume を打鍵したときに使う。

context-handover watcher が `/dispatcher-resume auto op=<OP>` を打鍵したときも使う。/org-start ではない(ワーカー・窓口は生きている前提。キュレーターは常駐しない)。

The English summary is being prepared. Showing the original description.

See how to install

Files included (3)

  • SKILL.md37.7 KB
  • references/rationale.md3.2 KB
  • SKILL.md.in34.2 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

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

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

前提:

  • ワーカー / 窓口のペインは前 session から生きたまま残っている。 新たに spawn しない(/org-start ではない)。キュレーターは常駐しない(起動中の curator が居れば Step 5 で追跡を引き継ぐ)。
  • 自ペイン(name=dispatcher)も生きている。secretary が send_keys で /clear → /dispatcher-resume を打鍵した直後の状態。pane_id / peer_id は 変わっていないはずだが、必ず観測し、観測で確定できた値だけを state.db に atomic 更新する(確定できなかった値は書かず既存値を保持する。Step 0 / Step 2)。
  • 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 から残っている。新規作成・初期化・削除しない(既存値からそのまま継続。 消すと前 session からの監視連続性が壊れる)。
  • handover ファイルが存在しないか古すぎる場合は、/org-start を案内して停止する。
  • /clear は /loop の予約を消さない。前 session の監視ループの予約は /clear の後も 残っており、同じ指示文で /loop をもう一度打つと予約が 2 本になる。監視ループを張る前に 必ず CronList で確かめる(Step 5。経緯は .claude/skills/dispatcher-resume/references/rationale.md §4)。

自動引き継ぎ(auto op=<OP> 付きで呼ばれたとき)

context-handover watcher(tools/context_handover_watch.py)が /dispatcher-handover auto op=<OP> → /clear → /dispatcher-resume auto op=<OP> を打鍵する。 手順は通常の resume と同じで、違いは次の 3 つだけ:

  • 完了の event(末尾「イベント記録」)に op=<OP> を付ける。watcher はこの行で復帰の完了を判定する。 Step 0 の前の already_consumed に落ちた場合(watcher の再送など)も、(i) と unknown の 分岐の終わりに同じ形の行を note=already_consumed で 1 行書く。初期化はやり直さない。
  • Step 6 の後に、/clear の前後に届いて会話から消えた入力を処理する(Step 6.5)。
  • 窓口への DISPATCHER_RESUMED / DISPATCHER_RESUMED_IDLE は通常どおり送る。

輸送層(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 する)。/loop 3m の予約が /dispatcher-resume 自身を反復対象に握っていると監視サイクルのたびに本 skill が再発火するので、 この stale 再発火 / 重複起動 を Step 0 に入る前に遮断する(経緯と各分岐の理由は .claude/skills/dispatcher-resume/references/rationale.md)。

  1. live / consumed の handover 状態を 存在ベースで判定する(now との時刻比較に 依存しない):
    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 に倒さず、 監視対象が実際に 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 として数える。「unknown」は live に数えないが、(ii) にも 倒さない。終端処理は (i) と同じ(早期 exit + 監視ループの予約を CronList で確かめて 1 本にする)とし、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 する。監視ループの予約を 1 本にしてから終える: CronList で予約を一覧し、/dispatcher-resume を反復対象に握っている予約があれば CronDelete で消す。そのうえで Step 5 の 2 と同じ手順で監視ループの予約を数え、 0 本なら Step 5 の monitoring 専用ディレクティブ(INVARIANT(loop-prompt) 準拠の /loop 3m ...)で張り、2 本以上なら 1 本を残して CronDelete で消す(/loop を打っても 既存の予約は上書きされず、2 本目として足される)。既に monitoring ディレクティブで 回っていれば当該サイクルは no-op heartbeat(何も出力しない)。再発火の事実だけ 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 を再生成 してくれる)。

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: ペイン生存確認

handover の ## 監視外の run に「監視外: <task_id>(ペインなし)」とある task_id も、下の判定 (list_peers / list_panes)で引き直す。ペインが在れば監視対象に戻す(書き手の判定が 誤りでも監視から落とさない)。確定して不在なら記録のずれとして Step 6 の briefing に task_id を 一覧で載せ、WORKER_PANE_EXITED は送らず、監視対象にも入れない。確定できなければ監視対象・active のまま残す。

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 照合の起点にするので、欠けると pane_id の 無いファイルとして扱われ、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)のいずれかを満たせば、 まず CronList で監視ループの予約(prompt に worker-monitoring.md と 「監視ループ 1 サイクル」を含むもの)を数える:

    • 1 本: 前 session の予約が /clear を越えて残っている。それが監視を続けるので /loop を張らない
    • 2 本以上: 1 本を残して CronDelete で消す(重複した監視ループは同じサイクルを 二重に回す)
    • 0 本: 下記の monitoring 専用ディレクティブを渡して /loop 3m で worker monitoring を 再開する(prompt を省略しない)

    0 本のときの再開は「/loop で監視を再開します」と 宣言するだけでは武装されない — 宣言はターン終了と同時に失効するため、必ず 本ターン内で /loop を実 invoke すること(窓口側も inspect_pane で実行痕跡を 裏取りし、無ければ send_keys で再点火する運用である):

<!-- INVARIANT(loop-prompt): `/loop` の prompt 引数に skill 自身(`/dispatcher-resume`)や 他のスラッシュコマンドを渡さない。skill 実行ターン内で prompt を省略して `/loop` を 起動すると、反復対象としてアクティブな slash command が捕捉され、本 skill が 3 分ごとに 自己再帰する(経緯は references/rationale.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 に通知して待機する(前 session の予約が残っていても消さない。 次のサイクルが監視対象なしを見て、worker-monitoring Step 7 の手順で自分で止まる):

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 6.5(自動引き継ぎのときだけ): /clear の前後に届いた入力を処理する

auto op=<OP> で呼ばれ、../.state/context/dispatcher-late-input-<OP>.md があるときだけ行う。 このファイルは watcher が旧会話記録から抜き出したもので、引き継ぎを始める直前から /clear の後 までに届いた入力(チャネルのメッセージ・/loop の反復・人の入力)が届いた順に並んでいる。

  1. Read で読み、各入力をいま届いたものとして処理する(ワーカーやキュレーターからの報告なら 通常どおり ack・転送する)。handover ファイルに処理済みと書かれている入力は飛ばしてよい (拾い直しは欠落より重複を許す側に倒してあるので、同じ入力が両方に載ることがある)。 /loop の反復は処理しない(監視ループの次のサイクルが同じことをする)。
  2. 読み終えたら rename する(同じ op のファイルを 2 回処理しない):
    mv ../.state/context/dispatcher-late-input-<OP>.md ../.state/context/dispatcher-late-input-<OP>.consumed.md
    

ファイルが無ければ何もしない(拾い直す入力が無かった)。別の op のファイルは読まない。

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 は live の .md だけを .prev.md に退避し .consumed.md には触らないので、次の resume の mv で上書きされるまで残る)
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

自動引き継ぎ(auto op=<OP>)のときは同じ行に op=<OP> と loop=<armed|kept|idle> (Step 5 で /loop を張った / 残っていた予約を使った / 監視対象なし)を足す。watcher はこの行で 復帰の完了を判定し、loop の値で監視ループの確認をするかを決める。already_consumed に 落ちた再送では note=already_consumed で同じ形の行を書く。

やってはいけないこと

  • 新規にディスパッチャー / キュレーターを spawn する(既に生きている)
  • ワーカーに勝手に SUSPEND / SHUTDOWN を送る
  • 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) 参照)

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

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

The English summary is being prepared. Showing the original description.

suisya-systems/claude-org-ja5Updated Oct 19, 2026

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

The English summary is being prepared. Showing the original description.

suisya-systems/claude-org-ja5Updated Oct 19, 2026

組織の生きているペイン(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`)。 外側が tmux のときに今の tmux を分割してワーカー(と dispatcher)を並べる `split-window` コマンドも出す。 特定のペインの画面を直接見たい・入りたい・並べて見たい、attach コマンドを知りたいという依頼で発動。 自分で attach / split はせず・ペインも一切変更しない(コマンド文字列とペイン一覧表を表示するのみ)。 作業委譲(org-delegate)・ダッシュボードで状況一覧(org-dashboard)・watcher 停止(org-attention-stop) には発動しない。

The English summary is being prepared. Showing the original description.

suisya-systems/claude-org-ja5Updated Oct 19, 2026

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 はしない(明示起動推奨ポリシー)。

The English summary is being prepared. Showing the original description.

suisya-systems/claude-org-ja5Updated Oct 19, 2026

`/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 落として」等で発動。

The English summary is being prepared. Showing the original description.

suisya-systems/claude-org-ja5Updated Oct 19, 2026

人間が承認したスコープの内側で triage → worker 派遣 → verify → push → PR 作成 → CI 監視 を完了駆動で自走し、PR ごとに merge gate で停止する窓口用のベルトコンベア。 「この範囲は自走してよい」「triage 上位の S 級バグを空き pane 分まで流して」等、 人間がスコープ承認を明示して複数候補を順に流したいときに窓口が起動する。

The English summary is being prepared. Showing the original description.

suisya-systems/claude-org-ja5Updated Oct 19, 2026

See all skills by suisya-systems

Report a problem with this skill