SNA

ランタイム

ランタイムアダプタ、AgentProvider 内部構造、ランタイムごとの差分を整理します。

各ランタイムは共通の AgentProvider インタフェースを実装するクラスとして 接続されます。アダプタは core/providers/{claude-code,codex,opencode,grok,cursor}.ts、 ACP を話すランタイム (Grok Build と Cursor) は core/providers/acp/base.ts を共有します。

対応ランタイム概要

SNA は、product が 1 つの CLI に固定されず、workflow に合う runtime を 選べるように設計されています。次の表は product 観点の概要です。細かな 機能対応は 機能 × ランタイムマトリクス で確認できます。

ランタイム向いている用途強みTradeoff
Claude CodeAnthropic model と安定した local coding session、豊かな permission behavior が必要な場合。CLI behavior が成熟していて、tool-use UX が良いです。Thinking/tool input delta streaming と token/cost metadata が詳しいです。呼び出し/セッションごとに stateless なので daemon pooling はありません。Permission approval は SNA との双方向通信ではなく hook ベースです。
Codex多数の session、one-shot job、頻繁な runtime reuse が必要な low-latency product integration。RuntimePool で daemon を再利用し、thread ごとの cwd 変更をサポートします。Item lifecycle event と shell output delta が豊富です。Codex native config shape が別にあり、Claude Code の stream-json のような tool input delta は露出しません。
OpenCodeOpenCode をすでに使っている app、または OpenCode model/provider 設定を HTTP daemon として使いたい app。Pooled daemon と SDK-backed HTTP path を使えます。1 つの cwd で repeated prompt を処理しやすいです。Daemon は single-cwd で、一部 runtime mutation は respawn が必要です。Event detail は OpenCode stream が出す範囲に依存します。
Grok BuildGrok Build と公開 protocol surface である ACP を使いたい session。SNA の shared ACP adapter を使い、bidirectional permission request と単純な stateless session lifecycle を持ちます。Runtime pooling はなく、model/cwd 変更には respawn が必要です。Token/tool detail metadata は Claude/Codex より薄めです。
CursorCursor を主な作業環境として使い、Cursor subscription-backed headless CLI を SNA から動かしたい場合。cursor-agent と既存の Cursor login を使います。ACP permission、Cursor model selection、model-id reasoning variant を利用できます。Daemon pooling はなく、model/cwd 変更には respawn が必要です。Setup はユーザーの Cursor CLI 認証状態に依存します。

以下では、この product-level choice の裏側にある adapter 内部構造を説明します。

AgentProvider

interface AgentProvider {
  name: string;
  isAvailable(): Promise<boolean>;
  spawn(opts: SpawnOptions): AgentProcess;
  complete(opts: CompleteOptions): Promise<CompletionResult>;
  // ...
}

interface AgentProcess {
  send(message: string, opts?): void;
  interrupt(): void;
  setModel(model: string): void;
  setPermissionMode(mode: PermissionMode): void;
  applyPatch(patch: SessionPatch): PatchResult;
  respondToPermission(approved: boolean): void;
  kill(): void;
  on(event: string, handler): void;  // AgentEvent を emit
}

applyPatch()PATCH /agent/session が使うフィールドごとの ディスパッチフックです。各ランタイムアダプタがどのフィールドをインプレースで 適用でき、どれが respawn-with-history-replay を要するかを決めます。

ランタイムごとの戦略

ランタイム転送状態プール?
claude-codeclaude -p (one-shot) + claude --resume (replay)呼び出しごとに statelessいいえ
codexcodex app-server デーモン、stdio 上の JSON-RPC永続デーモン、マルチスレッドはい
opencodeopencode serve デーモン + SDK HTTP永続デーモン、single-cwdはい
grokgrok agent stdio (stdio 上の Agent Client Protocol — Grok Build CLI)セッションごとに statelessいいえ
cursorcursor-agent acp (stdio 上の Agent Client Protocol — Cursor CLI)セッションごとに statelessいいえ

Codex と OpenCode ランタイムアダプタは RuntimePool 経由でデーモンを共有 します。セッションを開くとき、プールが (provider, cwd, config) で 照会され、互換のデーモンがあれば再利用してコールドスタートコスト を節約します(Codex 約 2 秒、OpenCode 約 3 秒)。

Grok Build は、SNA で初めてワイヤプロトコルに公開標準 (ACP)を採用したランタイムでした。 2 番目の ACP-speaking ランタイムとして Cursor が加わったことで、 共有ロジックは core/providers/acp/base.ts に抽出されました — JSON-RPC pump、initialize/session/new ハンドシェイク、session/updateAgentEvent 変換、双方向 session/request_permission (+bypassPermissions 自動承認)、ランタイム間 resource block history インジェクションまで。各サブクラスには実際に異なる部分だけを残します: CLI パス探索、spawn 引数、任意の認証ステップ (Cursor の authenticate({methodId:"cursor_login"}))、ベンダ拡張通知の prefix (_x.ai/* Grok、cursor/* Cursor)、ランタイム固有の tool-call unwrap。

ランタイム間の history replay は、ACP セッションの最初の session/prompt に正規化された会話履歴を 1 個の ACP resource content block として埋め込む方式で扱います — 機能マトリクスページの ランタイム間 history replay にまとめています。

Cursor はユーザーがすでに済ませた cursor-agent login をそのまま使います (macOS Keychain の cursor-access-token / cursor-refresh-token → Cursor サブスクリプションを利用)。CURSOR_API_KEY を別途発行する必要は ありません。SNA は spawn の環境変数をそのまま渡し、子プロセスは ユーザーがインタラクティブに使うときと同じ資格情報を使います。Reasoning level はモデル ID 自体にエンコードされます (gpt-5.3-codex → level 4 なら gpt-5.3-codex-high に変換)。reasoning-level.tsapplyCursorReasoning がその変換を行い、effort family に属さないモデル (composer-*auto など) はそのまま通過します。

RuntimePool

  • prepare(opts, provider): 既知の cwd に対してデーモンを事前 warm-up。
  • findExisting(spawnOpts): セッション spawn 用の strict マッチ (設定が揃っている必要)。
  • findCompatible(provider, cwd): completion() / runOnce() の 単発呼び出し用の loose マッチ (MCP、hooks、permission mode は 無視)。
  • shutdown(handle): 参照カウントが 0 になったら graceful 終了。

Claude Code はプーリングしません。CLI 自体が stateless なので、典型的 なセッション粒度では呼び出しごとの spawn がデーモン resume と 十分に競争力を持ちます。

SNA が ACP だけをランタイム層にせず、高忠実度のネイティブランタイムアダプタを 維持する理由は SNA と ACP で扱います。

クロスランタイム設定

すべてのランタイムで使える 2 つのレイテンシ設定:

  • reasoningLevel: 0..5: ランタイム非依存、最軽量から最重量 まで。reasoning-level.ts が Claude Code の --effort、Codex の model_reasoning_effort、 Grok Build の --effort、Cursor のモデル ID サフィックス (gpt-5.3-codex-high 等) に翻訳します。OpenCode はこのフィールドを 無視します。
  • providerOptions.serviceTier: Codex 専用。Codex の /fast スラッシュコマンドをミラーする (値: "priority", "flex", "batch")。Claude Code には意図的に自動マッピングしません。 Claude Code の /fast は別の課金プールを持つ別の MODEL バリアント だからです。

全ランタイムにわたる機能ごとの互換性については 機能 × ランタイムマトリクス で確認できます。

目次