Communityコーディング&開発github.com

aipoch/remote-compute-ssh

SSHリモートコンピュートを評価・活用し、GPU、大容量メモリ、並列・バッチ処理、モデル推論、バイオインフォマティクスなど長時間の科学計算をどこで実行するかを選択するためのスキルです。短いリモートコマンドと非同期ジョブをサポートし、自動収集・分析を行います。

remote-compute-ssh とは?

このスキルは、SSHを介したリモートコンピュートをカバーし、直接実行とSlurmサブミッションの両方を提供します。ホストの一覧表示、ハンドルの作成、短いリモートコマンドの実行(callCommand)、ホスト知識ドキュメントの読み書き、そして非同期ジョブの完全なライフサイクル(サブミット→job_idの保存→IDによる非ブロッキングスナップショットの読み取り→収穫→分析ターン→成果物の公開)をサポートします。 `host.compute`は制御プレーンREPLカーネルでのみ動作し、`repl_execute`ツール(JavaScript)を使用して実行する必要があります。PythonやRのデータカーネルでは利用できません。ユーザーはセッションカタログから有効なコンピュートホストを発見し、それらを評価して選択することができます。 非同期ジョブAPIは、長時間実行される計算(数分から数時間)のために設計されています。`submitJob`は即座に`job_id`を返し、ジョブがバックグラウンドで実行されます。ジョブ完了後、アプリは自動的に出力を収穫し、新しい分析ターンを開始します。収穫の安全境界(ファイルあたり最大100 MiB、ジョブあたり最大500 MiB、ディスク空き容量2 GiBの確保)が組み込まれています。 Slurmジョブの場合、このスキルは`#SBATCH`ディレクティブを介したリソース要求を処理し、Open-Scienceがサブミッション、スケジューラステータスポーリング、キャンセル、収穫を管理します。環境アクティベーションは、`~/.open-science/environments/<name>.sh`にある論理名を使用してサポートされており、直接実行とSlurmジョブの両方で利用できます。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/aipoch/open-science/tree/HEAD/resources/skills/remote-compute-ssh

Installed? Explore more コーディング&開発 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

このスキルは、直接実行およびSlurmサブミッションを含む、SSHを介したリモートコンピュートをカバーします。ホストの一覧表示、ハンドルの作成、短いリモートコマンドの実行(callCommand)、ホスト知識ドキュメントの読み書き、そして非同期ジョブの完全なライフサイクル(サブミット → job_idの保存 → そのIDによる非ブロッキングスナップショットの読み取り → 収穫 → 分析ターン → 成果物の公開)を行います。

host.computeの実行場所: host.computeは制御プレーンREPLカーネルでのみ動作します。以下のすべての例は、repl_executeツール(JavaScript)を使用して実行してください。このツールはhost.mcpをホストする同じカーネルです。python/rデータカーネルにはhost.computeがありません(SSHと承認はサンドボックスワークスペースの外側に留まります)。python/rセルから呼び出すと、host.compute is undefinedエラーで失敗します。

実行場所を選択する

このセッションで有効になっているコンピュートホストのみが表示または呼び出し可能です。1つのカタログでそれらを発見してください。各エントリにはselectedまたはavailableのロールがあります。空でない選択済みプールは実行指示です。タスクの必要に応じて、1つ以上の選択済みホストでツールベースのタスク作業を実行します。プールに優先順位はなく、自動的なマルチホストスケジューリングを意味するものでもありません。ホストが選択されていない場合は、利用可能なエントリから選択してください。より詳細な評価が必要な候補についてのみdetails()を読み取ってください。

カタログに存在しないプロバイダIDを推測したり再利用したりしないでください。無効なホストをユーザーが指定しても、そのホストは呼び出し可能になりません。このセッションで最初に有効にする必要があることを説明してください。使用可能なホストがない場合は、ブロッカーを説明し、ユーザーにどう進めるかを尋ねてください。

const hosts = await host.compute.listHosts()
const selectedHosts = hosts.filter((host) => host.role === 'selected')
const candidates = selectedHosts.length > 0 ? selectedHosts : hosts

各リスト項目は、provider_id、display_name、shape、execution_mode、status、roleを含むコンパクトなサマリーです(last_probe_ok、probe_failed、またはnot_probed)。last_probe_okは、最新の永続化されたプローブが成功したことを意味します。ライブ接続性を主張するものではありません。知識ドキュメントとリソースプローブスナップショットは、発見結果から意図的に除外されています。

APIリファレンス

// このセッションで有効なホストを、ロールを持つコンパクトなカタログとして一覧表示します
const hosts = await host.compute.listHosts()

// 互換性のある発見名は引き続き使用可能です。どちらも無効なホストを非表示にします。
const visibleHosts = await host.compute.listRegistered()
const selectedHosts = await host.compute.listPreferred()

// 特定のホストへのハンドルを作成します(ネットワーク呼び出しなし)
const c = host.compute.create('ssh:<alias>')

// 短いリモートコマンドを実行します(承認拒否/ホスト到達不能/タイムアウト時は例外をスロー)
const result = await c.callCommand('<シェルコマンド>', '<承認カードのための1行の意図>', {
  loginShell: true, // デフォルト: true — このコマンドの前にログインプロファイル、次に読み取り可能な~/.bashrcを実行します
  timeoutSeconds: 60 // オプション — ホストは省略時に独自のデフォルト(60秒)を適用します
})
// result → { exit_code, stdout, stderr, truncated }

// 永続化された操作手順と独立したリソースプローブスナップショットを読み取ります。
// docは常に正確に保存されたテキストです(手順が保存される前は''を含む)。
// probeは、このホストが一度もプローブされたことがない場合、明示的にnullです。
const info = await host.compute.details('ssh:<alias>', { mode: 'read' })

// 永続化されたホスト知識ドキュメントにメモを追加します(エージェント書き込み; 32 KB上限が適用されます)。
// 追加はdocのみを変更します。プローブの観測結果をコピーしたり変更したりすることはありません。
await host.compute.details('ssh:<alias>', {
  mode: 'append',
  text: '\n## ノート\n<日付>にXを学習しました'
})

// または、ホスト知識ドキュメント全体を置き換えます。置き換える前に再度読み取ってください。特に、上記で追加した場合は、oldTextが永続化されたdocと完全に一致する必要があります。
const latest = await host.compute.details('ssh:<alias>', { mode: 'read' })
await host.compute.details('ssh:<alias>', {
  mode: 'replace',
  text: '<新しい完全なドキュメント>',
  oldText: latest.doc
})

docを操作手順と永続的なホスト知識として扱ってください。probeを日付付きの観測結果として扱ってください。リソース値は変化する可能性があり、スケジューラを検出しても、ジョブの送信やアカウント、パーティション、キューの選択が許可されるわけではありません。ドキュメントの不一致やdetails_conflictエラーが発生した場合は、再度読み取り、ドラフトを最新のドキュメントとマージしてから再試行してください。リソースのみのプローブ更新では、docは変更されず、置き換えの競合も発生しません。書き込み後、再度読み取って保存内容を確認してください。成功した追加または置き換えの結果は{ ok: true }のみです。書き込み結果にはdocやprobeは含まれません。書き込み結果からフィールドを読み取るのではなく、常に再度読み取って、永続化された正確なdocを確認してください。

loginShell: trueの場合、リモートのBashログインプロファイルが最初に実行され、次にOpen-Scienceが読み取り可能な場合に~/.bashrcをソースしようとします。.bashrcは非インタラクティブシェルのために早期に戻ることが意図的に可能であるため、そのようなガードの後に宣言された変数は利用できません。.bashrcがない場合は何も起こりません。loginShell: falseに設定すると、どちらの初期化ステップもなしでコマンドが実行されます。初期化の失敗は、通常のコマンド結果/エラー動作を通じて報告されます。

APIリファレンス(非同期ジョブ)

長時間実行される計算(数分から数時間)にはsubmitJobを使用してください。即座にjob_idを返します。ジョブはリモートホストでバックグラウンド実行されます。ジョブが完了すると、アプリは自動的に出力を収穫し、まだ終了結果を読み取っていない場合は新しい分析ターンを開始します。サブミッション結果から正確なjob_idを作業コンテキストに保存してください。再発見のための履歴ジョブスキャンは意図的にありません。ステータスと結果の読み取りは、その保存されたIDのみを使用し、非ブロッキングのローカルスナップショットを返します。

ローカル入力の場合、srcはエージェントセッションワークスペースからの相対パスです。これはファイル書き込みツールが使用するのと同じワークスペースです。そこにスクリプトまたは小さな生成された入力を書き込み、その相対パスを渡してください。Open-Scienceは承認とディスパッチの前に受け入れられた入力をスナップショットします。任意の絶対ローカルパスを渡したり、アプリ管理のnotebooks/...ディレクトリにファイルをコピーしたりしないでください。絶対srcは、それがhost.artifactPath(versionId)によって返された正確なパス、またはノートブックコンテキストですでに供給されている正確な登録済みセッション入力パスである場合にのみ有効です。

// 上記でセッションカタログから選択した`candidates`を再利用します。

// 非ブロッキングジョブをサブミット — ユーザーが承認した後すぐに戻ります。
// コンピュートホストの設定された実行モードが、直接SSHまたはSlurmを選択します。
const c = host.compute.create('ssh:<alias>')
const job = await c.submitJob(
  '<承認カードのための1行の意図>', // 承認カードに表示されます
  '<シェルコマンド>', // リモートで実行するコマンド
  {
    environment: 'protein-gpu', // オプションの論理名; 以下の環境アクティベーションを参照
    timeoutSeconds: 3600, // オプション; デフォルト24時間、最大7日間
    inputs: [
      { src: 'in.dat', dstFilename: 'in.dat' }, // エージェントセッションワークスペースファイルをステージング
      { remotePath: 'ssh:<alias>/<abs_path>' } // リモートファイルをリンク(転送なし)
    ],
    outputs: [
      '*.result', // 注目(デフォルトの可視性)
      { glob: '*.json', visibility: 'featured' }, // 明示的に注目
      { glob: '*.log', visibility: 'hidden' }, // 非表示(診断用、カードに表示されない)
      { glob: 'checkpoints/**', residency: 'remote' } // リモートに残す — left_on_remoteに記録
    ],
    harvest: {
      exclude: ['work/**'], // これらのパスを収穫しない
      maxFileMb: 100, // 単一ファイルのハード上限(100 MiB)
      maxTotalMb: 500 // ジョブあたりのハード上限(stdout / stderrを含む)(500 MiB)
    }
  }
)
// job → { job_id, provider_id, status: 'submitted' | 'queued', remote_workdir }
const savedJobId = job.job_id // 後の依存ステップのためにこの正確なIDを保持
return { ...job, job_id: savedJobId }

保存されたジョブスナップショットを読み取る

ジョブの状態または結果が関連する場合に、保存されたIDを使用します。.status()と.result()は、すべての状態で非ブロッキングローカル読み取りです。完了を待ったり、SSHをトリガーしたり、別の収穫を開始したりしません。.result()には収穫されたファイルリストも含まれます。両方の呼び出しがfollow_up_deliveryを報告します。最終的な.result()読み取りは、フォールバックを抑制する場合はsuppressedを、そのフォールバックがすでにディスパッチフェンスを越えた場合はcommittedを返します。.status()スナップショットは、収穫されたファイルリストを省略するため、pendingのままです。古いジョブを検索するのではなく、サブミッションの正確なIDを使用してください。

const snapshot = await c.attachJob(savedJobId).result()
if (!snapshot.result_final) {
  return {
    job_id: savedJobId,
    status: snapshot.status,
    result_final: false,
    follow_up_delivery: snapshot.follow_up_delivery
  }
}
return snapshot

result_final: trueのみを最終結果として扱います。これは自動応答の準備ができていることを意味します:success、failed、timeoutはローカル収穫をまだ待機している可能性がありますが、cancelledとerrorは部分出力収集を待たずに最終です。output_filesにはローカルで実際に利用可能なファイルのみが含まれます。空のリストはリモート出力がないことを証明するものではありません。アプリはバックグラウンドでプロバイダのポーリングと収穫を所有します。未読の最終結果は後のエージェントターンで配信されます。最終的な.result()スナップショットは、そのフォールバックを抑制する場合はfollow_up_delivery: 'suppressed'を、自動配信がすでに競合に勝って権威あるものである場合はcommittedを報告します。.status()は完全な結果を消費することはありません。

直接SSHまたはSlurm

コンピュートホストの設定された実行モードが、各ジョブの起動方法を選択します。direct_sshは、SSHターゲットでコマンドをデタッチされたプロセスとして実行します。slurmはsbatchでサブミットします。クラスターに必要な#SBATCHディレクティブをcommandの先頭に配置してください。Open-Scienceがサブミッション、スケジューラステータスポーリング、キャンセル、収穫を所有します。自分でsubmitJobの周りでsbatch、squeue、scancelを呼び出さないでください。

Slurmステータスエラーまたはキャンセル失敗については、Slurmトラブルシューティングを参照してください。その例外的なパスでは、compute.callCommandを使用して同じジョブとその出力を検査し、ユーザーの既存のタスク承認範囲内でリカバリを実行できます。通常のサブミッションはコンピュートAPIに任せてください。

設定されたモードについてはlistHosts()を、プロバイダ固有のディレクティブについてはdetails()を読み取ってください。ジョブごとにモードを上書きしたり、ワークロードのみから推測したりしないでください。Slurmが利用できないかスクリプトを拒否した場合は、返されたエラーと具体的な次のステップ(たとえば、アカウントやパーティションディレクティブを追加するなど)を報告してください。ワークロードをログインノードで直接静かに再実行しないでください。

Open-Scienceはパーティション、アカウント、CPU、メモリ、GPUなどの通常の単一ジョブディレクティブを受け入れます。ワークロードのランタイムにはtimeoutSecondsを設定してください。スケジューラの割り当て制限は、1つの#SBATCH --time=値ディレクティブで設定できます。それが存在しない場合、Open-ScienceはtimeoutSecondsからデフォルトの割り当て制限を導出します。Open-Scienceはジョブ名、作業ディレクトリ、stdout、stderrのディレクティブを所有します。ジョブ配列は避けてください。1つのOpen-Scienceジョブが1つのスケジューラジョブと1つの出力収穫を追跡するためです。独立した作業は別々のジョブとしてサブミットし、必要に応じてセッションの同時実行制限を使用してください。

Slurmの場合、リソースは1行に1つの#SBATCH --option=値ディレクティブ(または#SBATCH --exclusiveのような値なしフラグ)で要求してください。レガシーなresourcesオプションは説明メタデータです。CPU、メモリ、GPUを割り当てるものではありません。timeoutSecondsはワークロードのランタイムを制限し、キュー待機時間は制限しません。#SBATCH --timeはスケジューラの割り当て制限を設定します。どちらもキュー開始時間の約束ではありません。

非ブロッキングジョブのstatus()とresult()スナップショットには、既知の場合はscheduler_job_id、ジョブレベルのエラーがある場合はerror: { code, message }、観測またはサブミッションのリカバリに注意が必要な場合はlast_poll_errorが含まれます。保留中の理由や遅延したアカウンティング行は、ワークロードが失敗したことを意味しません。サブミッションが確認されていない場合は、報告されたジョブIDとプロバイダ診断を使用して、再度サブミットするかどうかを判断してください。Open-Scienceは自動的に重複をサブミットしません。

環境アクティベーション

オプションのenvironment値はシェルコマンドではなく論理名です。Open-Scienceは、直接ジョブとSlurmジョブの両方で、ワークロードの前に~/.open-science/environments/<name>.shをソースします。名前は1〜64文字の英数字、ピリオド、アンダースコア、またはハイフンで、英数字で始まる必要があります。ファイルとそれが参照するすべてのソフトウェア/キャッシュパスは、実行ノードから見える必要があります。

サブミッションでこのアクティベーションファイルが見つからないと報告された場合は、コンピュート環境セットアップスキルをロードして、ユーザーまたはホスト管理者がOpen-Scienceの外部で実行するための正確なセットアップ、修復、および削除手順を準備してください。ユーザーが計画を適用した後、ユーザー管理のアクティベーションを検証し、再試行してください。conda名を推測したり、サイエンスジョブにインラインインストールを追加したり、アクティベーションを.bashrcに隠したりしないでください。コマンドがホストのデフォルト環境を意図的に使用する場合は、environmentを省略してください。

収穫の安全境界

  • 宣言された出力ファイルはstdoutとstderrの前に選択されます。ログは残りのジョブあたりの予算を使用します。
  • アプリは、ファイルあたり100 MiBまたはジョブあたり500 MiBを超えるモデル指定の制限を拒否します。
  • 収穫はまた、2 GiBの固定空きローカルディスク容量を保持します。収まらないファイルはリモートに残ります。

動作の境界

  • ジョブ実行中: 会話はオープンです。ユーザーはメッセージを送信できます。他のタスクを処理できます。各ステータス/結果クエリは、現在のローカルスナップショットで即座に戻ります。
  • ジョブ完了時: 終了結果を積極的に読み取らなかった場合、アプリは自動的に新しい分析ターンを開始します。このフォールバックをトリガーすることはありません。

ジョブステータスの確認(非ブロッキング読み取り、情報提供用)

// 非ブロッキングDB読み取り — SSHなし。会話の中間でステータススナップショットが必要な場合に使用します。
const handle = c.attachJob(job.job_id)
const s = await handle.status()
// s → {
//   job_id, scheduler_job_id?, status, result_final, cancellation?, exit_code,
//   error?, last ...

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

関連スキル