name: ssh-ops description: | SSH 経由でリモートホストに対するオペレーションを実行する。 サーバー稼働確認 (health check)、設定ファイル配信とリロード (config push)、 ログ取得と分析 (log fetch) の 3 軸をカバーする ops piece。 選ぶべき場合: タスクが「SSH で〜したい」「リモートサーバーで〜を実行」「サーバーから〜を取得」等 選ぶべきでない場合: ローカル作業のみ、Web 調査のみ、Office 加工のみ 事前条件: - admin が `config.yaml` の `ssh.enabled: true` を設定済み - 利用する SSH 接続が登録され、TOFU host key 検証が完了 (Settings → User Folder → SSH Connections → 該当接続 → Test) - ジョブ owner に接続への grant がある (private は owner 自身、global は admin の grant) 詳細: docs/ssh.md (operator runbook) と docs/tools/ssh-tools.md (LLM 向け) triggers: keywords: ["SSH", "リモート", "サーバー", "デプロイ", "ヘルスチェック", "ログ取得", "remote"] max_movements: 50 initial_movement: execute movements: - name: execute edit: true persona: ops-operator instruction: | ## 最初のステップ: タスク把握と接続の選定 1. Glob で input/ と output/ の現状を確認する 2. タスク本文を読み、以下のどの軸かを判定する (複合も可): - Health check: uptime / df -h / free -m / process status / journalctl 等で状態確認 - Config push: ローカルで作成・編集した設定を SshUpload で配信 → SshExec でリロード - Log fetch: SshDownload でリモートのログを取得 → ローカルで grep / 集計 / 分析 3. タスクで指定された SSH 接続 ID を確認する。指定が無く接続候補が複数ある場合は `complete({status: "needs_user_input", missing_info: "どの SSH 接続を使うか"})` で確認する ## SshExec の使い方 - 単発コマンド: `SshExec({connection_id, command})` - output は JSON envelope (`{stdout, stderr, exit_code, truncated, ...}`)。 `truncated: true` の場合は出力が大きすぎる → `SshDownload` で file 経由に切り替える - 機密値 (token / password) は command 文字列に直接渡さない。リモート側の env や config に置く - 接続ごとに deny-list / allow-list が設定されていることがある。`command_rejected` エラーは admin に許可パターン追加を相談する (ローカルで回避してはいけない) ## SshUpload / SshDownload の使い方 - リモートパスは接続の `remote_path_prefix` 配下のみ書き換え可能。違反は `path_not_allowed` で reject - ローカルパスは workspace の output/ または input/ 配下を推奨 - 大きなファイル: 上限は接続/グローバル設定の `max_upload_size_mb` / `max_download_size_mb` - Download 先のファイルが既にある場合は `local_target_exists` で reject される。 旧版を消すかリネームしてから再実行する ## エラーハンドリング (詳細は docs/tools/ssh-tools.md の error code 表) - `host_key_not_verified`: TOFU 未完了。 `complete({status: "needs_user_input", missing_info: "SSH 接続 の host key を UI で検証してください (Settings → User Folder → SSH Connections → Test)"})` で停止する - `host_key_mismatch`: MITM 疑い。**自動でリトライしない**。 `complete({status: "aborted", abort_reason: "host_key_mismatch:
"})` で停止する - `abuse_locked`: 連続失敗で接続がロック。 `complete({status: "needs_user_input", missing_info: "接続が までロックされています。admin に force-unlock を依頼してください"})` で停止する - `no_grant` / `access_denied`: 権限不足。admin に grant 追加を依頼するよう user に報告して停止する - `connect_timeout` / `auth_failed` 等の一時失敗: 同じ command を最大 2 回まで再試行。 それ以上は `complete({status: "aborted", abort_reason: "..."})` ## 調べ物 (Web 検索) - 不明なコマンド・オプション、エラーメッセージ、設定手順が出てきたら WebSearch で調べてよい。 ヒットしたページや公式 docs の本文は WebFetch、JS レンダリングや操作が要るページは BrowseWeb で読む - 設定テンプレート / インストーラ / tarball を URL から取得して配信したい場合は DownloadFile で output/ または input/ に落とし、SshUpload でリモートへ送る - 検索結果を鵜呑みにしてリモートで破壊的・不可逆なコマンドを実行しない。出典を確認し、不安なら停止して user に確認する ## 成果物 ops の結果は output/report.md にまとめる。**機密値は記録しない**: - 実行した command (機密値はマスク) と使用した接続 ID - SshExec の場合は stdout/stderr の要点 (全文ではなく要約。重要な行のみ転載) - SshUpload/SshDownload の場合は転送したファイル名 + サイズ - 観測した状態 / 異常があれば項目立てて記述 - 推奨アクション (異常があれば「再起動を提案」等) または「異常なし」の明示 ## 終了 / 遷移方法 - **次の verify へ**: `transition({next_step: "verify"})` - **必要情報不足で停止**: `complete({status: "needs_user_input", missing_info: "...", why_no_default: "..."})` - **致命的失敗で打ち切り**: `complete({status: "aborted", abort_reason: "..."})` allowed_tools: [SshExec, SshUpload, SshDownload, SshListConnections, WebSearch, WebFetch, DownloadFile, BrowseWeb, Read, Write, Bash, Glob, Grep] allowed_ssh_connections: ['*'] default_next: verify rules: - condition: output/report.md に ops 結果をまとめた next: verify - name: verify edit: false persona: reviewer instruction: | ops 結果を確認する。 確認手順: 1. Glob で output/report.md の存在を確認する 2. 報告書が無い、または内容が抽象論だけで実行結果が記載されていない場合は execute に差し戻す 3. Read で report.md を読み、以下をチェック: - 実行した command / 接続 ID が記録されているか - 観測結果 (stdout 要点 or 転送ファイル一覧) が記載されているか - 異常があった場合、推奨アクションが書かれているか - **機密値 (token / password / 秘密鍵 fingerprint 全体 / .env 内容等) が漏れていないか** 4. 不足があれば `transition({next_step: "execute", summary: ...})` で差し戻す: [判定] needs_fix ## 問題点 - [報告書の項目] 何が問題か ## 期待する修正 - 何をどう直すべきか ## 合格基準 - 再レビューで何を確認するか ## 次にやること - execute で最初に着手すべき具体的な作業 5. **機密値漏れを検出した場合は ABORT** (差し戻さない、ファイルにも残さない): `complete({status: "aborted", abort_reason: "secret_leak: report.md contained credential"})` ## 合格時のユーザーへの返答 `complete({status: "success", result: ...})` で output/report.md の要点を会話調で返す。 result そのものが user に表示される最終回答 (「report.md を確認」のような参照ではなく内容を書く)。 - 1 行目からいきなり本題: 「✅ 完了」等のメタ文言は禁止 - 観測した状態 + 推奨アクションを構造化して提示 - 異常無しなら明示する ## 終了方法のまとめ - 合格: `complete({status: "success", result: "ユーザー向け最終回答"})` - 修正必要: `transition({next_step: "execute", summary: "差し戻し指摘"})` - 機密漏れ: `complete({status: "aborted", abort_reason: "secret_leak: ..."})` - 技術的失敗: `complete({status: "aborted", abort_reason: "..."})` allowed_tools: [Read, Glob, Grep] default_next: COMPLETE rules: - condition: ops 報告が不足している next: execute