ディスパッチャーのコンテキストを圧迫したまま session を続けるのを避けるため、 monitoring 状態(active workers / 直近 polling cursor / pending escalations)を handover ファイルに書き出し、secretary の指示で /clear → /dispatcher-resume の 流れで新しいディスパッチャー session を開始する準備をする。 Secretary から DISPATCHER_HANDOVER peer message を受領したとき、または ディスパッチャー自身が context が長くなったと判断したときに使う。
wsl-windows-chrome-screenshot
WSL のワーカーから Windows 版 Chrome を headless で叩き、WSL 側に立てたプレビュー サーバの画面を PNG で撮るレシピ。
サーバ起動と撮影を 1 つの Bash 呼び出しにまとめ、 その呼び出しだけ sandbox を外す・1 枚目は捨て撮り・出力先は UNC でワークツリー、 という固定手順と、撮れていないときの症状の弁別(`ss -ltnp` / WSL 側 curl)を含む。
「WSL から Windows Chrome で画面を撮る」「rondo の画面のスクリーンショットを撮る」 「before/after を撮り比べる」「ライト / ダークを撮り分ける」等で発動。撮影を伴わない UI 実装・テストには発動しない。
含まれるファイル(1)
- SKILL.md12.1 KB
SKILL.md(原文)
インストールする前に、エージェントに与えられる指示の中身を確認できます。
WSL から Windows Chrome で画面を撮る
Linux 側の Chrome は共有ライブラリ不足で起動しない環境なので、Windows 版 Chrome を
headless で使う(rondo#318 の申し送り、knowledge/raw/archive/2026-09-20-wsl-windows-chrome-file-url-screenshots.md)。
以下は rondo#314 / #318 / #350 / #351 / #352 で繰り返し踏んだ手順を固定したもの。
どの失敗もエラーが原因を指さず、PNG が「撮れてしまう」ことが多い。
0. sandbox を外す撮影の実行は窓口が行う
§1 の dangerouslyDisableSandbox: true の呼び出しは、auto mode のワーカーでは分類器に
[Safety Bypass Flag] で拒否される(2026-09-22、2 回。sandbox 内で Chrome を 1 回起動する
probe も拒否)。同じスクリプトは窓口が流して撮れている。よって役割を分ける。
- ワーカー: サーバ起動・撮影・停止を 1 本にまとめた撮影スクリプトを
.worker-scratch/に用意し、sandbox 内でプレビューが起動する(curl が 200)ことまで確かめ、 そのまま流せる 1 行のコマンドを窓口への報告に書く。sandbox 解除は自分で要求しない。 1 回でも拒否されたら再要求しない(繰り返すとロックアウトされる)。 - 窓口: スクリプトを読んでから sandbox 外で 1 回だけ流し、撮れた PNG が Chrome の 接続拒否画面(§2)でないことを確かめて、merge gate のページに載せる。
1. サーバ起動と撮影は 1 つの Bash 呼び出しに入れ、その呼び出しだけ sandbox を外す
sandbox は Bash 呼び出しごとに PID / network 名前空間を分けるため、
- 別呼び出しで起こしたサーバはその呼び出しの終了と同時に死ぬ(
setsidしても畳まれる。run_in_background: trueなら生きるが、次の呼び出しの curl からも Windows Chrome からも届かない) - Chrome 側も sandbox 内から叩くと
<3>WSL (N - ) ERROR: UtilConnectUnix:526: socket failed 1だけを出して PNG を 1 バイトも書かない(WSL interop の unix socket が bwrap に塞がれる。 エラー終了はしない)
よってサーバ起動・ヘルスチェック・撮影・停止をまとめた 1 呼び出しを
dangerouslyDisableSandbox: true で流す。build / verify / git は sandbox 内のままでよい。
CHROME="/mnt/c/Program Files/Google/Chrome/Application/chrome.exe"
UNC='\\wsl.localhost\Ubuntu-24.04\home\happy_ryo\work\org\workers\<proj>\.worktrees\<task>\.worker-scratch\shots'
PORT=7361
shoot() { # shoot <name> <scheme 0=dark|1=light> <url>
"$CHROME" --headless=new --disable-gpu --hide-scrollbars \
--blink-settings=preferredColorScheme=$2 --window-size=2560,1440 \
--virtual-time-budget=4000 --screenshot="$UNC\\$1.png" "$3"
}
mkdir -p .worker-scratch/shots
node .worker-scratch/preview-$PORT.mjs > .worker-scratch/preview.log 2>&1 &
SRV=$!
for i in $(seq 1 20); do curl -fsS -o /dev/null "http://127.0.0.1:$PORT/?lang=en" && break; sleep 1; done
shoot warmup 1 "http://127.0.0.1:$PORT/?lang=en" # 捨て撮り(§2)
shoot after-en 1 "http://127.0.0.1:$PORT/?lang=en"
shoot after-ja 1 "http://127.0.0.1:$PORT/?lang=ja"
kill $SRV
tail -5 .worker-scratch/preview.log
& で起こしたプロセスはその呼び出しの終了で死ぬので後始末も自然に済み、
pgrep -f / pkill -f を使わずに済む(Bash ツールは zsh -c '<コマンド全文>' で
起動するため、同じコマンド内に殺したいパターン文字列があると pgrep -f が
その zsh 自身を拾って自殺する。Exit code 144 だけが返る。[3] のブラケット trick も
同一コマンド内に生の文字列がある限り効かない)。
while readループの中で撮るときは Chrome の stdin を</dev/nullにする。 塞がないと chrome.exe がループの入力を読み尽くし、1 画面目しか撮れない。- プレビューを
sh -cや npm 経由で起こすならexec node ...で起動し、$!を node の pid にする(間に親シェルが挟まるとkill $SRVが node に届かず残る)。残ったサーバがあると、 次の実行が古いビルドを撮るかEADDRINUSEになる。起動前にポートの使用状況を確かめ、 止めてよいのはこのタスクで自分が起動し pid を控えたプレビューだけ。自分のものでない プロセスが使っていたら止めずに、§6 のとおり別のポートを選ぶ。
2. サーバ起動直後の 1 枚目は必ず ERR_CONNECTION_REFUSED になる
同一呼び出し内で curl が 200 を返した後でも、Chrome の 1 枚目だけ 「このサイトにアクセスできません / ERR_CONNECTION_REFUSED」の PNG になる (2 枚目以降は同じ URL で正常。独立した 2 回の実行で再現)。WSL2 の localhost forwarding が Windows 側からの初回接続で張られるまでのラグ。curl のヘルスチェックを強化しても検出できない ので、撮影ループの先頭に捨て撮りを 1 枚置く。判別はバイト数でよい (2560x1440 のエラー画面はこの環境で 33,866 bytes 固定)。
3. 出力先は UNC でワークツリーへ書く
/mnt/c/Users/<user>/AppData/Local/Temp/... への mkdir は sandbox の write allowlist 外で
Read-only file system になる。Chrome には UNC でワークツリーを渡すのが通る(上の $UNC)。
既存の Temp 直下へ直接置くならディレクトリを作らず r<issue>-<name>.png のように
タスク識別子を名前に入れる(並走ワーカーと衝突しない)。
成功時は NNNNN bytes written to file ... を stdout に吐く。
この行が出ないときは撮れていない(ファイルの有無より先にこの行を見る)。
4. ライト / ダークは preferredColorScheme、値は 0=dark / 1=light
headless Chrome は既定で Windows 側の OS テーマ(この環境では dark)に従う。
--blink-settings=preferredColorScheme=1 でライト固定。2 を渡すとエラーにならず
ライトのまま撮れるので、「ダークのつもりでライトを撮った」が無言で起きる。
ライトとダークのバイト数はほぼ必ず違うので、md5sum が一致したら固定できていない。
5. 症状の弁別
| 見えるもの | 切り分け | 実体 |
|---|---|---|
Chrome が ERR_CONNECTION_REFUSED の PNG、WSL 側 curl は通る | 2 枚目が正常に撮れるか | §2 の初回ラグ。捨て撮りで解決 |
| Chrome も WSL 側 curl(別呼び出し)も届かない | 別の Bash 呼び出しで ss -ltnp | grep <port> が空 | サーバが呼び出し終了で死んでいる。§1 の 1 呼び出し化 |
PNG が生成されない / UtilConnectUnix: socket failed | — | 撮影側が sandbox 内。§1 で sandbox を外す |
curl は 200 だがログ末尾が EADDRINUSE | ログ末尾を読む | 別ワーカーの残骸が同じポートで応答している。§6 のとおりポートをずらす |
| 真っ白 / 無スタイルの PNG | 対象が file:// か | Windows Chrome は WSL パスを file:// で開けない。HTML と CSS を Windows 側 Temp へコピーしてから撮る |
ポート判定は「curl が通るか」ではなく別の Bash 呼び出しで ss -ltnp に残っているかで行う
(curl は同一呼び出し内なら死ぬ前に通ってしまう)。
6. before/after は git archive した別ツリーを別ポートで立てる
ワーカーは git stash 変更系も git checkout -- <path> も使えない。ワークツリーを触らずに
「前」を出す:
W=<worktree>
mkdir -p "$W/.worker-scratch/base"
git -C "$W" archive origin/main | tar -x -C "$W/.worker-scratch/base"
ln -sfn "$W/node_modules" "$W/.worker-scratch/base/node_modules" # install は 1 回で済む
sed -i 's/7334/7434/g' "$W/.worker-scratch/base/scripts/page-preview.mjs" # ポートを退避
npm --prefix "$W/.worker-scratch/base" run build
scripts/page-preview.mjs の new URL("../dist/...", import.meta.url) はスクリプトの位置から
解決されるので、コピー先の dist/ を見る。よって「前」と「後」が同時に立ち、同じ Chrome
ループで撮り分けられる。cd は使わず npm --prefix で回す。
「後」側もコピーしてポートを変えること。tracked ファイルを sed -i で書き換えると
git diff に混ざる。やむを得ず直接書き換えるなら、書き換える前に
cp <path> .worker-scratch/<name>.bak を取り、戻すときは command cp -f
(git show HEAD:<path> > <path> は commit 前のタスク変更ごと巻き戻す。
ワーカーは git checkout -- <path> / git restore --source= を hook で deny されている)。
戻したあと git diff -- <path> が撮影前の状態と一致することを確認する。
ポートは scripts/page-preview.mjs が 7334 決め打ち。削除済み worktree のプレビューが
生き残って掴んでいることがあるので、他ワーカーのプロセスは撃たず、複製してポートを
ずらす(ls -l /proc/<pid>/cwd が (deleted) なら残骸)。
7. 撮った PNG は必ず 1 回見る
--window-sizeの高さが足りないと下が切れた PNG がそのまま出る(エラーにならない)。- 判定対象が画面下端の要素(
sticky bottom-*等)のときは、高さ違いを 2 枚撮る (例 2560,1440 と 2560,1700)。低い方では下端に貼り付いて必ず見え、高い方では 静的位置に落ちるので、2 枚あると「貼り付いているのか、たまたま収まっているのか」が区別できる。 - 案と現物を比較する用途では、同じ
--window-size(= 同じ fold)で撮る。 - 言語は cookie に残る。英語で並べたいなら
?lang=enを明示する。 - SPA のハッシュ遷移(
#narrow/...)は headless の 1 発撮りでは効かず、トップが撮れる (バイト数がトップと完全一致するのが手がかり)。撮れないものは「撮れなかった」と報告に書く。
出典
knowledge/raw/archive/2026-09-21-wsl-chrome-screenshot-and-pgrep.md(rondo#314)knowledge/raw/archive/2026-09-21-windows-chrome-first-shot-refused.md(rondo#318)knowledge/raw/archive/2026-09-21-before-after-shots-need-two-builds-and-no-sandbox.md(rondo#350)knowledge/raw/archive/2026-09-21-screenshot-server-and-chrome-in-one-bash-call.md(rondo#351)knowledge/raw/archive/2026-09-21-wsl-chrome-shots-need-sandbox-off-on-both-legs.md(rondo#352)knowledge/raw/archive/2026-09-20-wsl-windows-chrome-file-url-screenshots.md(rondo#319、file://とウィンドウ高さ)knowledge/raw/archive/2026-09-22-screenshot-skill-blocked-by-auto-mode-classifier.md(rondo#411-#413、§0)
レビュー
まだレビューはありません。使ってみた感想をお寄せください。
同じリポジトリのスキル
概要と使いどころ
/dispatcher-handover で書き出した handover ファイルを読み込み、 ディスパッチャーを新しい session で復帰させる。/clear 直後の最初のターンで使う。 state.db の dispatcher_pane_id / dispatcher_peer_id を atomic に更新し、 worker monitoring の /loop 3m を再開する。 「ディスパッチャー復帰」「resume」「引き継ぎから再開」と secretary から指示された ときに使う。/org-start ではない(ワーカー・窓口・キュレーターは生きている前提)。
プロジェクトのゴール台帳(registry/goals/<owner>/<repo>.md)を人間と対話して新規作成・改訂する。 README と open Issue からゴール候補を推定して提示し、「何を目指すか」「何が起きていたら未達か」を 短く質問して条項を固め、書式検証(tools/work_discovery_goals.py validate)を通してから保存する。 「ゴール台帳を書きたい」「ゴールを設定して」「ゴール未設定と出た」「台帳エラーを直して」 「このプロジェクトの目標を決めたい」等や、/work-discovery の「ゴール未設定」「ゴール台帳エラー」案内を 受けて窓口が起動する。候補の提示そのものは /work-discovery の役目で本スキルではない。
組織の生きているペイン(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) には発動しない。
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 はしない(明示起動推奨ポリシー)。
`/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 落として」等で発動。