# DSL → Claude Agent SDK Options ブリッジ仕様

> **Status**: Proposal
> **Updated**: 2026-06-05
> **対象**: `src/adapters/claude-agent-sdk.ts`（および他 SDK アダプタのブリッジ層）
> **基準 SDK**: `@anthropic-ai/claude-agent-sdk` v0.2.141（型定義 `sdk.d.ts` 実測）

---

## 1. 問題意識

現行アダプタは、DSL から組み立てたエージェント定義を **`systemPrompt` 文字列に全部書き込み**、
SDK のネイティブ連携チャネル（`agents` / `skills`）を使っていない。

```ts
// 現状 src/adapters/claude-agent-sdk.ts buildOptions（抜粋）
opts.systemPrompt = systemPrompt;                 // ← agent 定義を文字列で丸投げ
if (this.guardrailHooks) opts.hooks = buildClaudeHooks(...);  // guardrail は hooks 連携済み
opts.tools = readonly ? ["Read","Glob","Grep"] : [..., "Edit","Write","Bash"];
opts.permissionMode = this.permissionMode;
// agents / skills / settingSources は未設定
```

これでは:

- **skills（SKILL.md）が SDK に渡らない** → progressive disclosure（必要時ロード）が働かない。
- **`agents` 未登録** → LLM がサブエージェントを Agent/Task tool で呼べない。
  **LLM にエージェントのルーティング（役割選択 / fanout）をさせるなら `agents` 登録は必須**。
  これが無いと「候補から LLM が選ぶ」モデル自体が成立しない。

ガードレイルは `hooks` で連携済みなので、欠落の核心は **skills** と **agents** の2つ。

---

## 2. SDK の連携チャネル（v0.2.141 実型定義）

| 関心事 | SDK オプション | 意味 |
|--------|---------------|------|
| エージェント定義 | `Options.agents: Record<string, AgentDefinition>` | サブエージェント登録。Agent/Task tool 経由で LLM が呼ぶ |
| 〃（単一カスタム） | `Options.systemPrompt: string \| string[] \| {preset}` | メインスレッドのカスタム system prompt |
| Skills | `Options.skills: string[] \| 'all'` / `AgentDefinition.skills: string[]` | SKILL.md を有効化（progressive disclosure） |
| ガードレイル（実行制御） | `Options.hooks: Partial<Record<HookEvent, ...>>` | PreToolUse 等でツール実行を block/deny |
| 権限（能力境界） | `Options.allowedTools` / `disallowedTools` / `permissionMode` / `canUseTool` | ツール許可・拒否・確認 |
| 設定ロード | `Options.settingSources: ('user'\|'project'\|'local')[]` | `.claude/settings.json`・skills・agents をディスクからロード |
| 拡張束 | `Options.plugins: SdkPluginConfig[]` | commands + skills + hooks をまとめる |
| MCP | `Options.mcpServers` | MCP サーバ |

### 2.1 `AgentDefinition` のフィールド（`sdk.d.ts:38`）

```ts
type AgentDefinition = {
  description: string;      // いつこのエージェントを使うか（LLM ルーティングの判断材料）
  prompt: string;           // このエージェントの system prompt
  tools?: string[];         // 許可ツール（省略時は親から継承）
  disallowedTools?: string[];
  model?: string;           // 'sonnet'|'opus'|'haiku' or full id or 'inherit'
  skills?: string[];        // このエージェントにプリロードする skill 名
  mcpServers?: AgentMcpServerSpec[];
  permissionMode?: PermissionMode;
  maxTurns?: number;
  effort?: 'low'|'medium'|'high'|'xhigh'|'max' | number;
  memory?: 'user'|'project'|'local';
  initialPrompt?: string;
  background?: boolean;
};
```

### 2.2 Skills の重要な性質（`sdk.d.ts:1670-1692`）

- skills は **context filter**。名前＋説明だけが文脈に入り、本体 SKILL.md は **Skill tool で必要時にロード**される。
- 「ファイルはディスク上にあり Read/Bash で到達可能。サンドボックスではない」。
- **したがって SKILL.md 本文を `systemPrompt` に貼ってはいけない**（progressive disclosure の意味が消え、トークンを浪費する）。`skills: ['x','y']` か `'all'` で有効化する。
- メインセッションは `Options.skills`、サブエージェントは `AgentDefinition.skills`。

---

## 3. ルーティングモデル（LLM ルーティング一択 = `agents` 登録必須）

**決定: LLM 内部ルーティング（モデル B）一択。`Options.agents` 登録は必須要件とする。**

役割選択・ドメイン特定・fanout 対象の選択は**自然言語理解を要する**（context-map と同じ問題で、
実行前に決定できない）。したがって選択は LLM に委ねるしかなく、SDK の subagent 機構に候補
エージェントを登録して **LLM が `description` を見て Agent/Task tool で委譲**する以外に成立しない。

### 仕様

- 候補エージェント群を `Options.agents: Record<id, AgentDefinition>` に登録する（**必須**）。
- 各 `AgentDefinition` に `description`（ルーティング判断材料）/ `prompt` / `tools` / `model` /
  `skills` / `permissionMode` を**個別**に持たせる。
- メインセッションの `systemPrompt` は「オーケストレータ/ルータの枠組み」を担い、各専門エージェントの
  定義は `agents[id]` 側に置く（**`systemPrompt` に全エージェント定義を丸投げしない**）。

### 却下: 外部ルーティング（単発 `query()` に systemPrompt 丸投げ）

runtime が事前にエージェントを 1 つ選んで `systemPrompt` に入れる方式は**却下**。
事前選択は自然言語タスクを読まないと不可能（前段の議論で確定）。`systemPrompt` 丸投げの現状実装は
このモデル専用であり、LLM ルーティングには対応できていない＝**作り直し対象**。

### backend 含意（重要）

`agents` 登録必須＝**ネイティブ subagent 機構を持つ backend でないと完全には成立しない**。

| backend | subagent 機構 | モデル B 対応 |
|---------|--------------|--------------|
| Claude `@anthropic-ai/claude-agent-sdk` | `Options.agents` | ✅ ネイティブ |
| OpenAI `@openai/agents` | `Agent.handoffs: Agent[]` | ✅ ネイティブ（handoff へ写像） |
| ~~Gemini `@google/genai`（生API）~~ | — | **不採用**（ADK に置換） |
| **Gemini ADK** `google/adk` | `sub_agents` + description 委譲 | ✅ ネイティブ（OpenAI 相当）= Google backend 採用 |
| Gemini CLI | subagents（markdown 定義） | △ ローカル定義依存（採用外） |
| ~~Cursor `@cursor/sdk`~~ | — | **サポート廃止**（依存 audit 不通過＋subagent 機構なし） |

→ 「全て SDK 経由でコンポーネント化」を厳密に満たすのは **Claude / OpenAI / Gemini-ADK**。
生 Gemini は runtime が subagent ルーティングを自前実装、Gemini CLI / Cursor は IDE・ローカル定義
束縛として別扱い。全 backend の詳細は **§7 Backend Capability Matrix** 参照。

---

## 4. DSL → SDK Options マッピング（決定版）

ブリッジ層は `systemPrompt` 文字列だけでなく、**`Options` オブジェクト全体**を組み立てる。

| DSL / artifact | → SDK | 備考 |
|----------------|-------|------|
| agent 定義（role_name/purpose/responsibilities/constraints/rules） | `agents[id].prompt`（Claude）／ `Agent.instructions`（OpenAI handoff） | レンダリングは既存 `buildTaskPrompt` を流用。**`systemPrompt` 丸投げはしない** |
| agent の `description` 相当（purpose 要約） | `agents[id].description` | **LLM ルーティングの判断材料**。必須 |
| 候補エージェント集合（selector で絞った群） | `Options.agents: Record<id, AgentDefinition>`（Claude）／ `Agent.handoffs`（OpenAI） | **必須**。これが LLM ルーティングの前提 |
| `can_execute_tools` | `agents[id].tools` | 現状の readonly 粗判定を DSL 由来へ |
| `mode: read-only/read-write` | `permissionMode` / tools 絞り込み | |
| `model_class` + `agent-runtime.config.model_mapping` | `agents[id].model` / `Options.model` | |
| cursor-skills（SKILL.md / 固定プロンプト手順） | **in-code 合成**: skill = subagent（`AgentDefinition` prompt=本体, description=用途）／ または skill = TS ハンドラ tool（`createSdkMcpServer`+`tool()` / function / ADK function） | ネイティブ `skills`（ディスク discovery）は**不使用**。in-code 注入で `settingSources:[]` 隔離を維持。手順塊→subagent、決定的処理→tool |
| guardrails + policy | `hooks`（既存）＋ `disallowedTools` / `permissionMode` | scope を hook matcher / tools 絞りに反映 |
| ルータ/オーケストレータ枠組み | `Options.systemPrompt` | 各エージェント定義ではなく「委譲の枠組み」のみ |
| 隔離（ローカルファイルを読ませない） | `settingSources: []`（Claude） | コンポーネント化要件。**明示必須**（既定は `.claude/` をロード） |

---

## 5. 最優先の実装ギャップ

| 優先 | ギャップ | 対応 |
|------|---------|------|
| **HIGH** | `agents` 未登録（＝LLM ルーティング不能） | 候補エージェントを `AgentDefinition` 群に変換し `Options.agents` に登録。`description` を必ず埋める。`systemPrompt` 丸投げを廃止。OpenAI は `handoffs`、Gemini は runtime 側ルーティング合成 |
| **HIGH** | skills 未連携 | SKILL.md をディスク配置し、DSL の skill 参照を `Options.skills` / `AgentDefinition.skills` にマップ。system prompt への本文インラインを廃止 |
| **HIGH** | 隔離されていない（ローカル `.claude/` 依存の可能性） | Claude は `settingSources: []` を明示。Cursor は IDE 束縛＝非隔離 backend として扱う |
| **MED** | tools 権限が粗い（readonly 二択） | `can_execute_tools` 由来の per-agent `tools` に置換 |
| LOW | plugins / mcpServers | 必要に応じて `AgentDefinition.mcpServers` / `Options.plugins` にマップ |

---

## 6. 現行実装の所在と変更点

- `src/adapters/claude-agent-sdk.ts` `buildOptions()`:
  - 追加（必須）: `opts.agents`、`opts.skills`、`opts.settingSources: []`。
  - 変更: `opts.tools` を DSL 由来の per-agent ツールへ。`opts.systemPrompt` は「ルータ枠組み」のみに縮小（エージェント定義の丸投げをやめる）。
  - 既存維持: `opts.hooks`（guardrail）、`permissionMode`。
- `src/adapters/openai-agents-sdk.ts`: 候補エージェントを `Agent` 群に変換し `handoffs` に登録（subagent 委譲）。
- `src/adapters/gemini-sdk.ts`（生 `@google/genai`）: **不採用・廃止**。Google backend は ADK に置換。
- `src/adapters/cursor-sdk.ts`: **サポート廃止・撤去**（依存 audit 不通過＋subagent 機構なし）。`@cursor/sdk` peer dep も削除。
- **ADK アダプタ（新規）**: 候補エージェントを ADK の `sub_agents` 階層へ変換し description 委譲に乗せる。
  runtime は TypeScript のため、ADK-TS を使うか、ADK(Python) を A2A / サブプロセス経由で呼ぶかは要確定（§8）。
- ブリッジ（DSL → Options 変換）は adapter の外（runtime のブリッジ層）に置き、adapter は受け取った
  Options 片を各 SDK に渡すだけにする。backend capability matrix（§3）で分岐。
- skills 本文は `systemPrompt` から除去（progressive disclosure に委ねる）。

---

## 7. Backend Capability Matrix（全 SDK）

ルーティングは LLM 内部ルーティング（§3）一択のため、**ネイティブ subagent 機構の有無**と
**ローカルファイル依存（隔離可否）**が backend 選定の決め手になる。

凡例: ✅ ネイティブ in-code / △ 可能だが制約あり / ❌ 機構なし（runtime 合成が必要） / 🔒 ローカル依存

| backend | 種別 | subagent ルーティング | tools | skills 相当 | guardrail | ローカル依存 / 隔離 | SDK 経由コンポーネント化 |
|---------|------|----------------------|-------|------------|-----------|---------------------|--------------------------|
| **Claude** `@anthropic-ai/claude-agent-sdk` | agent SDK | ✅ `Options.agents`（Agent/Task tool） | ✅ `allowedTools`/`disallowedTools`/per-agent `tools` | ✅ `skills`（progressive disclosure） | ✅ `hooks` + `permissionMode`/`canUseTool` | 既定で `.claude/` ロード 🔒 → **`settingSources:[]` で隔離可** | ◎（`settingSources:[]` 前提で完全 in-code） |
| **OpenAI** `@openai/agents` | agent SDK | ✅ `Agent.handoffs: Agent[]` | ✅ `tools`（function tools） | ❌（handoff+tools で代替） | ✅ SDK `guardrails` + `mcpServers` | なし（完全 in-code） | ◎ 最もクリーン |
| ~~**Gemini (raw)** `@google/genai`~~ | 生成 API | ❌ subagent なし | — | ❌ | ❌ | — | **不採用（ADK に置換）**。primitive 不足でモデル B を満たせない |
| **Gemini (ADK)** `google/adk`（py / ts / go / java） | agent FW | ✅ `sub_agents` 階層 + description 委譲 + Workflow/Task/A2A | ✅ tools | ❌（tools/sub_agents で代替） | △ callback / plugin / policy | なし（**code-first in-code**） | ◎（OpenAI 相当）= **Google backend はこれを採用** |
| **Gemini CLI** `google-gemini/gemini-cli` | CLI エージェント | ✅ subagents（`@agent` 委譲 + description 自動ルーティング） | ✅ tools（wildcard / MCP isolation） | △（CLI 機能依存） | ✅ Policy Engine | **強い** 🔒（`~/.gemini/agents` の markdown 定義） | △ CLI backend。ローカル定義依存（Cursor と同類） |
| ~~**Cursor** `@cursor/sdk`~~ | エージェント SDK | ❌ in-code 機構なし（単一 Agent のみ） | ✅ inline MCP | △ | ✅ hook callbacks | 既定隔離 | **サポート廃止**。①依存 audit を通らない ②候補 subagent を in-code 登録できずモデル B 不適 |

### 判断（確定）

- **採用 backend は Claude（要 `settingSources:[]`）/ OpenAI / Gemini-ADK の 3 つ**。いずれも
  ネイティブ subagent ＋ in-code 注入でモデル B・隔離要件を満たす。
- **生 `@google/genai` アダプタは不採用・廃止**。primitive 不足でモデル B を満たせず、runtime 自前合成は
  ADK で代替できるため保持価値がない。Google backend は **ADK 一本**。
- **Gemini CLI** はローカル markdown 定義依存（`~/.gemini/agents`）→ 非隔離。採用外。
- **Cursor は サポート廃止**。理由は ①`@cursor/sdk` が依存関係 audit を通らない、
  ②候補 subagent を in-code 登録する機構が SDK に無くモデル B 不適、の 2 点。
  `src/adapters/cursor-sdk.ts` と `@cursor/sdk`（optional peer dep）を撤去する。
- → ブリッジは採用 3 backend に対し、共通の最小契約（候補 AgentDefinition 群）を各機構
  （Claude `agents` / OpenAI `handoffs` / ADK `sub_agents`）へ写像する。

---

## 8. 残課題（未決）

- 軽量 skill（同一 context に instructions を軽くロードしたいだけのもの）を subagent ではなく
  「instruction テキストを返す tool」で表すかの線引き基準。
- ADK の組み込み方式: **ADK-TS を使う**か、**ADK(Python) を A2A / サブプロセス経由**で呼ぶか
  （runtime は TypeScript。ADK-TS の成熟度を確認のうえ確定）。
- 共通抽象（candidate AgentDefinition 群）→ Claude `agents` / OpenAI `handoffs` / ADK `sub_agents`
  への写像インターフェース型定義。

> **確定事項**:
> - ルーティングは **LLM 内部ルーティング（モデル B）一択**。候補登録（`agents`/`handoffs`/`sub_agents`）は必須。
> - 外部ルーティング（systemPrompt 丸投げ）は不採用。
> - **採用 backend = Claude / OpenAI / Gemini-ADK**。生 `@google/genai` アダプタは廃止。
> - **Cursor サポート廃止**（依存 audit 不通過＋in-code subagent 機構なし）。`cursor-sdk.ts` と `@cursor/sdk` を撤去。Gemini CLI は採用外（非隔離）。
> - **skills は in-code 合成**（subagent or TS ハンドラ tool）。ネイティブ `skills` ディスク discovery は不使用 → `settingSources:[]` 隔離を維持。skill と agent は同じ subagent 登録機構に統合。
