SDK のツール・権限・拡張
Agent SDK で自作ツール・MCP・ツール検索・権限・フック・サブエージェント・スキル・プラグイン・システムプロンプトを組み込む方法を、オプションと一覧表でまとめます。
Agent SDK のエージェントは、ツールを増やし、使える範囲を絞り、動きを途中で差し込むことで作り込みます。このページは、その手段(自作ツール・MCP サーバー・ツール検索・権限・フック・サブエージェント・スキル・プラグイン・システムプロンプト)を1か所にまとめたものです。
- 自作ツールは SDK 内蔵の MCP サーバー(プロセス内)として登録し、
mcp__<サーバー名>__<ツール名>で呼ばれます - ツールの許可は、フック → deny → ask → 権限モード → allow →
canUseToolの順で評価されます - フックは
query()に渡すコールバックで、ツールの実行前後や節目で自分のコードを動かします - サブエージェント・スキル・プラグインは、コードでもファイルでも定義できます(スキルはファイルのみ)
- システムプロンプトは、プリセット・
append・自前の文字列・出力スタイル・CLAUDE.mdの4通りで調整します - オプションの全フィールドは SDK の API リファレンス、全体像は Agent SDK の基本 にあります
自作ツール#
自作ツールを使うと、データベース・外部 API・アプリ固有の処理を Claude から呼べます。SDK 内蔵の MCP サーバー(自分のアプリのプロセス内で動き、別プロセスにはなりません)として登録します。
| やりたいこと | 方法 |
|---|---|
| ツールを定義する | Python は @tool、TypeScript は tool()。名前・説明・入力スキーマ・ハンドラーを渡す |
| Claude に登録する | create_sdk_mcp_server / createSdkMcpServer で包み、query() の mcpServers に渡す |
| 事前に承認する | allowedTools に入れる |
| 組み込みツールを Claude の文脈から外す | tools に、使う組み込みツールだけを並べる |
| 並列に呼ばせる | 副作用のないツールに readOnlyHint: true を付ける |
| Claude に読ませるエラー文を決める | isError: true を返して自分でメッセージを作る |
| 画像やファイルを返す | content に image や resource のブロックを入れる |
| 機械が読める JSON を返す | 結果に structuredContent を付ける |
| 大量のツールを扱う | ツール検索で必要なときに読み込む |
ツールの4つの要素#
- 名前:Claude が呼ぶための一意の識別子
- 説明:何をするツールか。Claude が使う場面を決めるのに読む
- 入力スキーマ:Claude が渡す引数。TypeScript は常に Zod のスキーマで、ハンドラーの
argsに型が付く。Python は{"latitude": float}のような名前と型の辞書で、SDK が JSON Schema に変換する(enum・範囲・省略可能なフィールド・入れ子のオブジェクトが要るときは、完全な JSON Schema の辞書も渡せる) - ハンドラー:Claude が呼んだときに動く非同期関数。検証済みの引数を受け取り、次のオブジェクトを返す
| 戻り値のフィールド | 必須 | 内容 |
|---|---|---|
content |
はい | 結果のブロックの配列。type は "text"・"image"・"audio"・"resource"・"resource_link" |
structuredContent |
いいえ | 結果を機械可読にした JSON オブジェクト。content と並べて返す |
isError |
いいえ | true にするとツールの失敗として伝わり、Claude が対応できる |
定義して呼ぶ#
import { tool, createSdkMcpServer, query } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
const getTemperature = tool(
"get_temperature",
"指定した場所の現在の気温を取得する",
{
latitude: z.number().describe("緯度"),
longitude: z.number().describe("経度"),
},
async (args) => {
const res = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}¤t=temperature_2m&temperature_unit=fahrenheit`
);
const data: any = await res.json();
return { content: [{ type: "text", text: `Temperature: ${data.current.temperature_2m}°F` }] };
}
);
const weatherServer = createSdkMcpServer({ name: "weather", version: "1.0.0", tools: [getTemperature] });
for await (const message of query({
prompt: "サンフランシスコの気温は?",
options: {
mcpServers: { weather: weatherServer },
allowedTools: ["mcp__weather__get_temperature"],
},
})) {
if (message.type === "result" && message.subtype === "success") console.log(message.result);
}
from typing import Any
import httpx
from claude_agent_sdk import tool, create_sdk_mcp_server, query, ClaudeAgentOptions, ResultMessage
@tool("get_temperature", "指定した場所の現在の気温を取得する", {"latitude": float, "longitude": float})
async def get_temperature(args: dict[str, Any]) -> dict[str, Any]:
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": args["latitude"],
"longitude": args["longitude"],
"current": "temperature_2m",
"temperature_unit": "fahrenheit",
},
)
data = response.json()
return {"content": [{"type": "text", "text": f"Temperature: {data['current']['temperature_2m']}°F"}]}
weather_server = create_sdk_mcp_server(name="weather", version="1.0.0", tools=[get_temperature])
options = ClaudeAgentOptions(
mcp_servers={"weather": weather_server},
allowed_tools=["mcp__weather__get_temperature"],
)
mcpServersのキーが、ツールの完全名mcp__{サーバー名}__{ツール名}のサーバー名になります。この名前をallowedToolsに入れると、確認なしで動きます- 1つのサーバーに複数のツールを並べられ、
allowedToolsには1つずつ書くか、ワイルドカードmcp__weather__*でサーバーの全ツールを指定します - 省略可能な引数は、TypeScript は Zod のフィールドに
.optional()を付けて既定値をハンドラーで補います。Python の辞書スキーマはすべてのキーを必須として扱うので、スキーマから外し、説明文に書いて、ハンドラーでargs.get()を使います - ツール検索は既定で有効で、SDK の MCP ツールも後回しにされます(Claude には名前の一覧だけが見え、全スキーマは必要なときに読み込まれます)。無効にすると、配列内の全ツールが毎ターン文脈を使います。TypeScript では、
tool()のextras引数かcreateSdkMcpServer()のオプションにalwaysLoad: trueを渡すと、そのツールの全スキーマを最初のプロンプトに残せます
ツールの注釈(annotations)#
MCP のツール注釈は、ツールの性質を示す任意のメタデータです。TypeScript は tool() の5番目の引数、Python は @tool の annotations キーワード引数で渡します。フィールドはすべて真偽値です。
| フィールド | 既定 | 意味 |
|---|---|---|
readOnlyHint |
false |
環境を変更しない。ほかの読み取り専用ツールと並列に呼べるかを決める |
destructiveHint |
true |
破壊的な更新をしうる。情報のみ |
idempotentHint |
false |
同じ引数の繰り返しが追加の効果を持たない。情報のみ |
openWorldHint |
true |
自分のプロセスの外のシステムに届く。情報のみ |
注釈は強制ではなくメタデータです。readOnlyHint: true のツールでも、ハンドラーがディスクに書けば書けてしまいます。ハンドラーの実際の動きに合わせます。
ツールの利用範囲を決める#
tools と許可・禁止のリストは、2つの層に効きます。可用性(ツールが Claude の文脈に出るか)と、許可(Claude が呼んだ呼び出しを承認するか)です。tools と素の名前の disallowedTools は可用性、allowedTools と範囲指定の disallowedTools は許可を変えます。タスク管理のツールを allowedTools に入れると、そのセッションで使えるようになります。
| オプション | 層 | 効果 |
|---|---|---|
tools: ["Read", "Grep"] |
可用性 | 列挙した組み込みツールだけが文脈に出る。ほかの組み込みツールは外れる。MCP ツールには影響しない |
tools: [] |
可用性 | 組み込みツールがすべて外れる。Claude は自分の MCP ツールだけを使える |
| 許可するツール | 許可 | 列挙したツールは確認なしで動く。ほかのツールも使えるが、呼び出しは権限の評価に回る |
| 禁止するツール | 両方 | "Bash" のような素の名前は、tools から省くのと同じにツールを文脈から外す。"Bash(rm *)" のような範囲指定は、ツールを文脈に残し、そのとおりに一致する呼び出しだけを拒否する |
組み込みツールを完全に外すには、tools から省くか、素の名前を disallowedTools(Python は disallowed_tools)に入れます。範囲指定の禁止ルールはツールが見えたままなので、Claude が試して1ターンを無駄にすることがあります。
エラーの扱い#
ハンドラーのエラーでエージェントのループは止まりません。SDK 内蔵の MCP サーバーが、捕まえなかった例外をエラー結果として返します。エラーの返し方で、Claude が読む内容が変わります。
| 起きること | 結果 |
|---|---|
| ハンドラーが捕まえない例外を投げる | MCP サーバーが、生の例外メッセージを持つエラー結果に変換する。Claude はそれを読み、ループは続く |
ハンドラーがエラーを捕まえ、isError: true(Python は "is_error": True)を返す |
Claude は自分で作ったメッセージを読む。どのリクエストが失敗したか、代わりに何を試すかなど、生の例外にない情報を足せる |
どちらでも、Claude は再試行・別のツール・失敗の説明ができます。生の例外では Claude が行動を決められないときに、自分で捕まえます。
画像とリソースを返す#
content 配列は text・image・audio・resource・resource_link のブロックを受け付け、同じ応答に混ぜられます。
- audio:TypeScript は、SDK がディスクに保存し、Claude には保存先のパスを書いたテキストが届く。Python は、audio ブロックを結果から落として警告を記録する
- resource_link:Claude には、名前・URI・説明を含むテキストのブロックとして届く。TypeScript では、アプリも user メッセージの
tool_use_resultのresourceLinksでリンクを受け取れる。Python では、SDK が CLI へ渡す前にテキストへ平らにするので、プロセス内ツールではresourceLinksのキーが作られない
画像のブロック(image)です。
| フィールド | 型 | 備考 |
|---|---|---|
type |
"image" |
|
data |
string |
base64 のバイト列。生の base64 のみで、data:image/...;base64, の接頭辞は付けない |
mimeType |
string |
必須。例:image/png・image/jpeg・image/webp・image/gif |
- URL のフィールドはありません。URL にある画像は、ハンドラーで取得して base64 にしてから返します
- PNG・JPEG・GIF・WebP は視覚入力として Claude に届きます。ほかの種類の画像はディスクに保存され、Claude にはパスがテキストで届きます
リソースのブロック(resource)は、URI で識別する内容を埋め込みます。生成したファイルや外部システムのレコードを返すときに使います。
| フィールド | 型 | 備考 |
|---|---|---|
type |
"resource" |
|
resource.uri |
string |
内容の識別子。どの URI スキームでもよい |
resource.text |
string |
テキストの内容。blob とどちらか一方 |
resource.blob |
string |
バイナリの内容の base64。TypeScript のみ。Python はバイナリのリソースを結果から落として警告を記録する |
resource.mimeType |
string |
任意 |
ブロックの形は MCP の CallToolResult 型のものです。
構造化データを返す#
structuredContent は、content とは別の、任意の JSON オブジェクトです。画像や文字列から読み取らせずに、正確な値を Claude に渡したいときに使います。設定すると、Claude には、その JSON と content の画像・リソースのブロックが届き、content のテキストのブロックは(構造化データと重複するとみなされて)渡されません。
補足
Python の @tool は、ハンドラーが返す辞書のうち content と is_error しか渡しません。Python で structuredContent を返すには、プロセス内の SDK サーバーではなく、独立した MCP サーバーを動かします。
MCP サーバーをつなぐ#
MCP(Model Context Protocol)は、エージェントを外部のツールやデータにつなぐオープンな標準です。MCP サーバーは、ローカルのプロセス・HTTP 接続・SDK アプリ内のどれでも動かせます(Claude Code の CLI 側の設定は MCP サーバーをつなぐ)。
for await (const message of query({
prompt: "プロジェクトのファイルを一覧にして",
options: {
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"],
},
},
allowedTools: ["mcp__filesystem__*"],
},
})) { /* ... */ }
options = ClaudeAgentOptions(
mcp_servers={
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"],
}
},
allowed_tools=["mcp__filesystem__*"],
)
サーバーは、コード(mcpServers)か、プロジェクトのルートの .mcp.json で指定します。.mcp.json は project の設定ソースが有効なとき(既定の query() では有効)に読まれます。settingSources を明示するなら "project" を含めます。
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
}
}
}
トランスポートの種類#
| 種類 | 使いどころ | 指定 |
|---|---|---|
| stdio | 同じマシンで動かすローカルのプロセス(stdin/stdout で通信)。ドキュメントが実行するコマンドを示すとき | command と args |
| HTTP / SSE | クラウドのサーバーやリモートの API。ドキュメントが URL を示すとき | type("http" か "sse")・url・headers |
| SDK MCP サーバー | コード内で自作ツールを定義する(別プロセスは起こさない) | createSdkMcpServer |
- ストリーミング可能な HTTP は
"type": "http"です。.mcp.jsonなどの JSON 設定では"streamable-http"が"http"の別名として受け付けられます。SDK のMcpHttpServerConfig型は"http"だけを宣言するので、コードで渡すサーバーは"http"を使います initializeの制御リクエストで登録した SDK MCP サーバーは、Claude Code がそのリクエストを処理した時点から接続を始めます
MCP ツールを許可する#
MCP ツールは、明示の許可がないと Claude は呼べません(ツールがあることは見えても呼べません)。名前は mcp__<サーバー名>__<ツール名>(例:github サーバーの list_issues は mcp__github__list_issues)で、allowedTools にワイルドカード * を使うと、サーバーの全ツールをまとめて許可できます。
ヒント
MCP へのアクセスには、権限モードよりも allowedTools を使います。acceptEdits は MCP ツールを自動承認しません(承認するのはファイル編集と、ファイルシステムの Bash コマンドだけ)。bypassPermissions は承認しますが、ほかの安全確認の大半まで無効にするので範囲が広すぎます。allowedTools のワイルドカードは、望んだサーバーだけを許可します。
サーバーが出すツールは、サーバーのドキュメントを見るか、system の init メッセージの tools 配列(mcp__ で始まる名前)で確かめます。init メッセージは最初のターンの接続待ちのあとに出るので、tools には、その時点で接続済みのサーバーと、キャッシュされたツール一覧を持つサーバーの mcp__ ツールが並びます。
接続のタイミング#
Claude Code は、options.mcpServers のサーバーを起動時に登録し、最初のターンの待ちが終わると init メッセージを出します。最初のターンを遅らせるかは、サーバーの種類で決まります。
| サーバーの種類 | 最初のターンを遅らせるか | 最初のターンの待ちの上限 |
|---|---|---|
| stdio、またはキャッシュされたツール一覧のない HTTP / SSE | 遅らせる(接続するまで) | MCP_TIMEOUT(既定 30 秒)。その期限で接続が失敗する |
| 以前の接続で Claude Code が保存した、キャッシュ済みのツール一覧を持つリモートサーバー | 遅らせない(キャッシュのツールが最初のターンから使える) | なし。最初のツール呼び出しで接続し、その接続には別のタイムアウトがある |
| プロセス内の SDK サーバー | 遅らせる(接続してツールを列挙するまで) | MCP_TIMEOUT(既定 30 秒)。接続の試行ごと。その期限で接続が失敗する |
.mcp.jsonやプラグインから読み込んだサーバーは、init メッセージでpendingになりがちです。options.mcpServersに stdio・HTTP・SSE のサーバーがあると、最初のターンはこれらの待機中のサーバーもMCP_TIMEOUTまで待ちます。options.mcpServersが空か SDK サーバーだけなら、最初のターンの待ちは2秒までです- ツール検索が有効(既定)なら、待つのは
alwaysLoad: trueで、まだ待機中のサーバーだけです。残りはバックグラウンドで接続を続けます。ツール検索が無効なら、待機中のサーバーすべてを待ちます。ToolSearchツールをdisallowedToolsなどで外した場合も、ツール検索なしで動きます permissionPromptToolNameを設定すると、最初のターンはそのツールのサーバーも、どの場合でもMCP_TIMEOUTまで待ちます- 最初のターンの待ちを自分で決めるには、
envにCLAUDE_CODE_MCP_STARTUP_WAIT_MS(ミリ秒。例:"5000")を入れます。ツール検索の可否にかかわらず、待機中のすべてのサーバーをその時間まで待ち、stdio・HTTP・SSE のMCP_TIMEOUTの待ちを置き換えます。0で待たずに進みます。permissionPromptToolNameのサーバーは、値にかかわらずMCP_TIMEOUTで待ちます。要件は Claude Code v2.1.274 以降です - 起動そのものを、init メッセージの前の別の段階で止めるには、
MCP_CONNECTION_NONBLOCKINGを0にして接続のバッチ全体を待ちます(待ちの上限は既定 5 秒で、MCP_CONNECT_TIMEOUT_MSのミリ秒で変えられます)。サーバーの設定にalwaysLoad: trueを付けると、ツールが最初のターンから完全なスキーマで使え、ツール検索の後回しの対象外になります
認証#
多くの MCP サーバーは認証が要ります。資格情報は、サーバー設定の環境変数やヘッダーで渡します。
// 環境変数で渡す(stdio サーバー)
mcpServers: {
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN },
},
}
// ヘッダーで渡す(HTTP / SSE サーバー)
mcpServers: {
"secure-api": {
type: "http",
url: "https://api.example.com/mcp",
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
},
}
.mcp.json では ${API_KEY} や ${API_TOKEN} の書き方で、環境変数が実行時に展開されます。
OAuth 2.1 は MCP の仕様にありますが、SDK はブラウザを開かず、対話的な OAuth の流れも動かしません。サーバーが認可のチャレンジを返し、保存済みのトークンがないと、そのサーバーのツールなしで実行が続き、ステータスは needs-auth になります(init メッセージの mcp_servers ではまだ pending に見えることもあります)。資格情報が要るかは、TypeScript は mcpServerStatus()、Python は get_mcp_status() で確かめます。資格情報は、OAuth の流れを自分のアプリで済ませ、得たアクセストークンをサーバーの headers に渡します。
エラーの扱い#
init メッセージ(system の subtype が init)に、各 MCP サーバーの接続状態が入ります。status は "pending"・"connected"・"failed"・"needs-auth"・"disabled" のどれかです。
"pending"は、それだけでは失敗ではありません。まだ接続していない、ツール一覧がキャッシュから出ていて最初の使用で接続する、接続の期限が切れた("pending"か"failed"になる)、のいずれかです- 使えないサーバーは、
"failed"と"needs-auth"を見て検出します - リモートサーバーは、
"connected"と報告したあとで状態が変わることがあります。接続が切れると"pending"に戻り、再接続を試みます。後からmcpServerStatus()(Python はClaudeSDKClient.get_mcp_status())を呼ぶと、前に接続を見たサーバーが"pending"になっていることがあります - 再接続が5回失敗すると
"failed"(再認可が要るなら"needs-auth")になります。手動で再試行するには、TypeScript はreconnectMcpServer()、Python はClaudeSDKClient.reconnect_mcp_server()です
トラブルシューティング#
| 症状 | 確認すること |
|---|---|
サーバーが failed |
init メッセージでどのサーバーか見る。環境変数や資格情報の不足(stdio は env が合っているか)、サーバーが未導入(npx のパッケージと Node.js の PATH)、接続文字列の誤り、ネットワーク(リモートの URL に届くか、ファイアウォール)を確かめる |
| ツールが見えるのに呼ばれない | allowedTools で許可しているか |
| 接続がタイムアウトする | 接続の上限は既定 30 秒。MCP_TIMEOUT(ミリ秒)で伸ばす。実行中のツール呼び出しの長さは MCP_TOOL_TIMEOUT。TypeScript では、1つの SDK MCP サーバーのツール呼び出しの上限を createSdkMcpServer() の timeout で指定できる。軽いサーバーを使う、エージェントの前にサーバーを温めておく、サーバーのログで遅い初期化の原因を見る、も有効 |
Tool output exceeds maximum allowed tokens |
成功した結果のうち画像を含まないものが25,000トークンを超えると、Claude Code が出力をファイルに保存し、パスを示すエラーに置き換える(エージェントが分けて読み戻せる)。トークンの上限は MAX_MCP_OUTPUT_TOKENS で変える。ツールが anthropic/maxResultSizeChars を宣言していない限り、成功したテキストの結果が50,000文字を超えると、トークンの上限にかかわらずファイルに保存される(サーバーがこの注釈を宣言する方法は MCP のページを見る) |
| SDK MCP サーバーからツールが消える | TypeScript SDK では、ツールの入力スキーマを JSON Schema に変換できないと、createSdkMcpServer() で作ったサーバーはそのツールをツール一覧から外し、SDK が警告を出す。Node.js では、コード CLAUDE_SDK_MCP_TOOL_SCHEMA_UNCONVERTIBLE のプロセス警告で、Tool "<name>" on SDK MCP server "<server>" was left out of the server's tool list, because its input schema cannot be converted to JSON Schema で始まる。警告の残りには、変換エラーのメッセージ(あれば)と、確かめて直すことが書かれる。TypeScript Agent SDK v0.3.286 より前は、変換できないスキーマが1つあるとサーバーのツール一覧の取得全体が警告なしに失敗し、そのサーバーのツールが1つも Claude に届かなかった |
環境変数は 環境変数一覧 にあります。
注意
データベースのサーバー(DBHub の execute_sql など)は、エージェントが出す SQL をそのまま実行します。書き込みも含みます。DBHub の設定ファイルで readonly = true にすると、INSERT・UPDATE・DELETE・DDL を拒否できます。接続文字列は、プロセスの環境の ${DATABASE_URL} から解決されるので、ファイルに書かずに済みます。
ツール検索#
ツール検索は、すべてのツール定義を文脈に先読みせずに、エージェントが必要なツールを探して読み込む機能です。数百〜数千のツールを扱えます。
- 文脈の効率:50個のツールで1〜2万トークンを使うことがある
- 選択の精度:30〜50を超えるツールを同時に読み込むと、選択の精度が落ちる
有効なときは、ツール定義は文脈から外れ、エージェントには利用できるツールの要約が渡されます。作業が、読み込み済みでない機能を要するとき、エージェントが検索します。標準では関連性の高い最大5個のツールが文脈に読み込まれ、それらを見つけたメッセージが SDK に圧縮されるまで、以降のターンでも使えます。圧縮後は、また必要になったときに探し直します。検索のたびに往復が1回増えますが、ツールが多ければ、毎ターンの文脈が小さくなる効果が上回ります。ツールが10個に満たず定義が文脈に余裕で収まるなら、先読みのほうがたいてい速いです。
設定#
既定では有効で、例外は次のとおりです。
- SDK が対応外とするモデルでは、ツール定義を先読みします。
ENABLE_TOOL_SEARCHの値では上書きできません - Microsoft Foundry の Azure ホストのデプロイは、サーバー側で拒否されるので、SDK が拒否を検出し、そのデプロイでは先読みに切り替えます。
ENABLE_TOOL_SEARCHで上書きできません - Google Cloud の Agent Platform では、モデルの世代で決まります。Claude Opus 4.5・Sonnet 4.5・Haiku 4.5 とそれ以降は有効。それより前のモデルは、サービング基盤が必要なベータヘッダーを拒否するので、先読みで、
ENABLE_TOOL_SEARCHでも上書きできません(Claude Code v2.1.221 より前は、ENABLE_TOOL_SEARCHを設定しない限り、Agent Platform のすべてのモデルで無効でした) ANTHROPIC_BASE_URLが自社以外のホストを指すと、多くのプロキシがtool_referenceブロックを転送しないため無効になります。ENABLE_TOOL_SEARCHで上書きできます
ENABLE_TOOL_SEARCH の値 |
動き |
|---|---|
| 未設定 | 有効。ツール定義は後回しにされ、必要に応じて見つける。上の例外では先読みに戻る |
true |
常に有効。ただし Microsoft Foundry の Azure ホストと、Claude 4.5 世代より前の Agent Platform のモデルでは先読みのまま。プロキシにもベータヘッダーを送り、tool_reference に対応しないプロキシでは要求が失敗する |
auto |
後回しにできるツール定義のトークン数を数え、モデルの文脈の窓と比べる。合計が窓の10%に達すると有効になり、それ未満なら全定義を先読みする |
auto:N |
auto と同じで、割合を指定する。auto:5 は5%で有効になる。小さいほど早く有効になる |
false |
無効。毎ターン、全ツール定義を文脈に読み込む |
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETASを設定すると、ツール検索は無効のままで、ENABLE_TOOL_SEARCHで上書きできません。組織は、Claude Code v2.1.227 以降で、管理設定によってツール検索を有効のままにできます- ツール検索は、リモート MCP サーバーも SDK 内蔵のサーバーも含む、登録されたすべてのツールに効きます。
autoでは、alwaysLoadの付かない MCP ツールと、必要なときに読み込む組み込みツールを合算して、1つの閾値と比べます。Bash・Read・Editなどの中核の組み込みツールは先読みされ、数えません。プラグインの Mod がツールを遅延させる、または先読みにすることもでき、そのぶん数が変わります - 値は
query()のenvに指定します。TypeScript はenvがサブプロセスの環境を置き換えるので...process.envを展開し、Python は継承した環境に重ねられます
for await (const message of query({
prompt: "適切なデータベースのクエリを見つけて実行して",
options: {
mcpServers: { "enterprise-tools": { type: "http", url: "https://tools.example.com/mcp" } },
allowedTools: ["mcp__enterprise-tools__*"],
env: { ...process.env, ENABLE_TOOL_SEARCH: "auto:5" },
},
})) { /* ... */ }
見つけやすくする#
検索は、問い合わせをツールの名前と説明に照合します。
ヒント
search_slack_messages のような名前は、query_slack より広い要求に当たります。説明も、「Search Slack messages by keyword, channel, or date range」のように具体的な語を入れたほうが、「Query Slack」のような一般的な語より多くの問い合わせに当たります。利用できるツールの分類を書いたシステムプロンプトの節を足すのも有効です。claude_code プリセットに append で足します。
| 限界 | 内容 |
|---|---|
| ツールの最大数 | カタログに10,000個 |
| 検索結果 | 1回の検索で、既定では最も関連性の高い最大5個 |
| 対応モデル | Claude Sonnet 4.5・Haiku 4.5・Opus 4.5 とそれ以降(Google Cloud の Agent Platform も同じ下限) |
権限#
SDK の権限は、権限モード・フック・allow/deny のルール・canUseTool コールバックで制御します(Claude Code 本体の考え方は 権限ルール と 権限モード)。
評価の順序#
Claude がツールを要求すると、SDK は次の順で判定します。
- フック:最初に動く。呼び出しを拒否するか、先へ流す。
allowを返しても、あとの deny と ask のルールは、フックの結果にかかわらず評価される。PreToolUseフックの allow では、重要なパスを対象にしたrm・rmdirによる削除は承認できない - deny ルール:
disallowed_toolsと settings.json のルール。当たれば、bypassPermissionsでもブロックされる。Bashのような素の名前の deny は、この評価の前にツールを Claude の文脈から外すので、この段階で調べるのはBash(rm *)のような範囲指定のルールだけ - ask ルール:settings.json の
ask。当たるとcanUseToolに回り、bypassPermissionsでも同じ。ユーザーの操作が要るツール(AskUserQuestion、サーバーが_meta["anthropic/requiresUserInteraction"]を設定した MCP ツール)は、allow ルールに当たっても常にコールバックに回る。dontAskでは、どちらも拒否される(その MCP の注釈は Claude Code v2.1.199 以降)。組織がaskにした claude.ai のコネクタのツールも、すべての呼び出しがコールバックに回り(bypassPermissionsでも、allow に当たっても)、理由Your organization requires approval for this toolが渡る。dontAskでは拒否される - 権限モード:有効なモードを適用する。
bypassPermissionsは、この段階に来たものを、重要なパスへのrm・rmdirを除いて承認する。acceptEditsは、許可するファイル操作を承認する。planは、ファイル編集とシェルの書き込みを、allow ルールにかかわらずcanUseToolへ送る。ほかのモードでは次へ回る - allow ルール:
allowed_toolsと settings.json のルール。当たれば承認される。ツール自身が承認できる呼び出し(作業ディレクトリ内のファイル読み取りや、読み取り専用の Bash コマンド)も、ルールなしでここで解決される。重要なパスへのrm・rmdirは、allow ルールでは承認されない canUseToolコールバック:ここまでで決まらなければ呼ばれる。dontAskではこの段階が飛ばされて拒否される。TypeScript でpermissionPrompts: 'none'を指定すると、コールバックは呼ばれず、PermissionRequestフックが決める機会を得て、決めなければ拒否される(Claude Code v2.1.259 以降)
TypeScript SDK は、評価の順序上、コールバックの前に呼び出しが自動承認される構成で canUseTool を渡すと、クエリを作るときに Node.js のプロセス警告を1回出します(警告のコードは CLAUDE_SDK_CAN_USE_TOOL_SHADOWED)。
permissionMode: 'bypassPermissions'"Read"のような素のallowedToolsの項目
Bash(ls *) のように指定子のある項目と acceptEdits では出ません。設定ファイル由来の allow ルールは、この検査から見えません。process.on('warning', ...) でコードに一致させて、記録や抑制ができます。すべての呼び出しに効かせたい検査は、PreToolUse フックで書きます。
allow と deny のルール#
allowed_tools と disallowed_tools(TypeScript は allowedTools / disallowedTools)は、評価の流れの allow と deny のリストに項目を足します。
| オプション | 効果 |
|---|---|
allowed_tools=["Read", "Grep"] |
Read と Grep は自動承認。ほかのツールも存在し、承認が要る呼び出しは権限モードと canUseTool に回る |
disallowed_tools=["Bash"] |
Bash の定義がリクエストから外れる。Claude は見えず、試せない |
disallowed_tools=["Bash(rm *)"] |
Bash は使える。書かれたとおりに rm * に一致する呼び出しは、bypassPermissions を含むすべてのモードで拒否される。/bin/rm を含むほかの Bash 呼び出しは権限モードに回る |
disallowed_tools=["*"] |
すべてのツール定義がリクエストから外れる。deny ではツール名のグロブが使え、"*" は全ツール、"mcp__*" は全サーバーの MCP ツールに当たる |
- allow ルールでツール名のグロブが使えるのは、文字どおりの
mcp__<サーバー>__の接頭辞のあとだけで、サーバー名の部分にグロブは使えません(mcp__puppeteer__*、mcp__github__get_*)。allowed_tools=["*"]や["mcp__*"]は、起動時の警告とともに無視され、何も自動承認しません ReadとEditの範囲指定ルールは、パターンを取ります。Edit(path)のルールは、WriteとNotebookEditを含む、ファイルを書く組み込みツールすべてに効きます。Write(path)のルールは、ファイルの権限検査では一致しません- 絶対パスは
//pathで書きます(Edit(//secrets/**)はディスク上の/secrets以下への書き込みを止める)。先頭がスラッシュ1つのEdit(/secrets/**)は、ルールの出どころを基準にします。allowed_toolsやdisallowed_toolsで渡したルールでは、セッションの作業ディレクトリです
注意
自動承認されたツールは canUseTool に届きません。acceptEdits・bypassPermissions・allow ルールのどれかで先に承認された呼び出しは、コールバックを通らないので、そこに置いた権限の検査は、そのツールに対して黙って迂回されます。allow ルールが自動承認しないのは、AskUserQuestion、requiresUserInteraction の MCP ツール、組織が ask にしたコネクタのツール、重要なパスへの rm・rmdir です。素の名前(Read、mcp__github__get_issue)は例外を除くそのツールのすべての呼び出しを自動承認し、Bash(npm test *) のような範囲指定は一致する呼び出しだけを自動承認します。
注意
allowed_tools は bypassPermissions を制限しません。列挙しなかったツールは allow ルールに当たらず権限モードに回り、そこで bypassPermissions が承認します。allowed_tools=["Read"] を permission_mode="bypassPermissions" と並べても、Bash・Write・Edit を含むすべてのツールが承認されます。特定のツールを止めたいなら disallowed_tools を使います。
閉じたエージェントを作るには、allowedTools と permissionMode: "dontAsk" を組み合わせます。列挙したツールが(どのモードも自動承認しない操作を除いて)承認され、ほかの、承認が要る呼び出しはすべて拒否されます。default で承認が要らない呼び出し(読み取り専用の Bash コマンド、Agent のように確認なしで動くツール、作業ディレクトリ内のファイル読み取り)は、列挙しなくても動きます。ツールを Claude の手の届かない所に置くには、素の名前を disallowedTools に入れます。
allow・deny・ask のルールは、.claude/settings.json で宣言的にも書けます。project の設定ソースが有効なとき(既定の query() では有効)に読まれます(設定キー一覧)。
権限モード#
権限モードは、query() で指定するか、ストリーミングのセッション中に動的に変えられます。指定しないと、Claude Code が開始のモードを決めます。そのセッションの設定ファイルの permissions.defaultMode、なければ組み込みの既定(auto モードのことがある)です。auto モードで始まるセッションは、素の Bash のような広い allow ルールを捨てます。default やそのルールに頼るアプリは、default を明示します。TypeScript Agent SDK v0.3.286 より前は、permissionMode を省くことは default を渡すことと同じでした。
| モード | 説明 | ツールの動き |
|---|---|---|
default |
標準 | モードによる自動承認はない。承認が要り allow ルールに当たらない呼び出しは canUseTool を呼ぶ |
dontAsk |
確認の代わりに拒否 | 確認が要る呼び出しはすべて拒否。allowed_tools やルールで承認されたものと、default で承認が要らないものは動く。組織が ask にしたコネクタ・ユーザーの操作が要るツール・重要なパスへの rm・rmdir は、事前に承認していても拒否される。canUseTool は呼ばれない |
acceptEdits |
ファイル編集を自動承認 | ファイル編集とファイルシステムの操作(mkdir・rm・mv など)を自動で承認する |
bypassPermissions |
権限検査を飛ばす | どのモードも自動承認しない操作を除き、確認なしで動く。注意して使う |
plan |
計画 | ソースを編集せずに調べて計画する。ファイル編集は自動承認されず、canUseTool を呼ぶ |
auto |
モデルが分類して承認 | モデルの分類器が、シェルコマンドやネットワーク要求などを審査して許可・拒否する |
acceptEdits が自動で承認するのは、ファイル編集(Edit・Write)と、ファイルシステムのコマンド mkdir・touch・rm・rmdir・mv・cp・sed です。どちらも作業ディレクトリか additionalDirectories の中のパスだけが対象です。範囲の外のパス・保護されたパス・重要なパスへの rm・rmdir は、自動承認されません。ほかのツール(ファイルシステムの操作でない Bash コマンド)は、通常の権限が要ります。
bypassPermissions について。
- フックは動き、必要なら操作を止められます
- Linux と macOS では、認識されたサンドボックスの外で root や
sudoで動かすと、Claude Code は起動を拒み、クエリは最初のターンの前に失敗します - deny ルール・明示の
askルール・フックは、モードの検査より前に評価され、ツールを止められます。組織がaskにしたコネクタのツール・ユーザーの操作が要るツール・重要なパスへのrm・rmdirは、canUseToolに回ります。クロスセッションのメッセージの安全策も効きます
plan モードについて。
- ファイル編集は、allow ルールに当たっても自動承認されず、
canUseToolに回ります。Claude Code v2.1.212 以降では、ファイルを変更するシェルコマンド(touchやrm)も同じくcanUseToolに回ります - TypeScript で
allowDangerouslySkipPermissions: trueとpermissionMode: 'plan'を併用しても、ファイル編集とファイルを変更するシェルコマンドはcanUseToolに回ります。あとでsetPermissionMode()でbypassPermissionsへ切り替えるための指定です - 計画を詰める前に、
AskUserQuestionで要件を確かめることがあります(SDK のセッションと入出力)
dontAsk モードは、権限の確認をすべて、canUseTool を呼ばずに拒否へ変えます。allowed_tools・settings.json の allow ルール・フックで承認されたものと、default で承認が要らない呼び出し(作業ディレクトリ内のファイル読み取り、Agent の呼び出し)は動きます。PreToolUse フックの allow は、重要なパスの削除を通しません。
注意
サブエージェントの継承:サブエージェントは、親のセッションの権限モードで動きます。例外は、AgentDefinition に permissionMode を指定し、かつ親が default・dontAsk・plan のときだけです。それでも "bypassPermissions" の値は適用されません。サブエージェントが bypassPermissions で動くのは、親自体がそうしているときだけです(Claude Code v2.1.267 以降)。サブエージェントは、メインより制約の緩い動きをすることがあるので、bypassPermissions を継承させると完全な自律のシステムアクセスを渡すことになります。
モードは、起動時に permission_mode / permissionMode で指定するか、ストリーミング中に set_permission_mode() / setPermissionMode() で変えます。新しいモードは、以降のすべてのツール要求にすぐ効きます。厳しく始めて、信頼が増えてから緩める(最初の方針を確かめたあとで acceptEdits へ切り替える)といった使い方ができます。
フック#
フックは、ツールの呼び出し・セッションの開始・実行の停止などのイベントに応じて、自分のコードを動かすコールバックです。次のことができます。
- 実行前に危険な操作をブロックする(破壊的なシェルコマンド、許可のないファイルアクセス)
- すべてのツール呼び出しを、監査・デバッグ・分析のために記録する
- 入出力を変換する(データの無害化、資格情報の注入、ファイルパスの付け替え)
- データベースの書き込みや API 呼び出しなど、慎重な操作に人の承認を求める
- セッションのライフサイクルを追う(状態の管理、後始末、通知)
Claude Code のシェルコマンド型のフックは フックの使い方 と フックのリファレンス にあります。ここでは SDK のコールバックを扱います。
動き方#
- イベントが発火する(ツールの呼び出し直前の
PreToolUse、結果を返したPostToolUse、サブエージェントの開始と停止、待機、終了) - SDK が、そのイベントに登録されたフックを集める。
options.hooksのコールバックと、対応するsettingSourcesが有効なときの設定ファイルのシェルコマンドのフックを含む matcherが、イベントの対象(例:ツール名)に照合してフィルターする。matcherのないフックは、そのイベントのすべてで動く- 一致した各フックのコールバックが、何が起きているか(ツール名・引数・セッション ID・イベント固有の詳細)を受け取る
- コールバックが決定を返す。操作の許可・ブロック・入力の変更・会話への文脈の注入
async def protect_env_files(input_data, tool_use_id, context):
file_path = input_data["tool_input"].get("file_path", "")
if file_path.split("/")[-1] == ".env":
return {
"hookSpecificOutput": {
"hookEventName": input_data["hook_event_name"],
"permissionDecision": "deny",
"permissionDecisionReason": "Cannot modify .env files",
}
}
return {}
options = ClaudeAgentOptions(
hooks={"PreToolUse": [HookMatcher(matcher="Write|Edit", hooks=[protect_env_files])]}
)
import { query, HookCallback, PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";
const protectEnvFiles: HookCallback = async (input, toolUseID, { signal }) => {
const preInput = input as PreToolUseHookInput;
const toolInput = preInput.tool_input as Record<string, unknown>;
const fileName = (toolInput?.file_path as string)?.split("/").pop();
if (fileName === ".env") {
return {
hookSpecificOutput: {
hookEventName: preInput.hook_event_name,
permissionDecision: "deny",
permissionDecisionReason: "Cannot modify .env files",
},
};
}
return {};
};
for await (const message of query({
prompt: "標準的なローカル開発用のデータベース設定で .env ファイルを作って",
options: { hooks: { PreToolUse: [{ matcher: "Write|Edit", hooks: [protectEnvFiles] }] } },
})) { /* ... */ }
使えるイベント#
| イベント | Python | TypeScript | 発火するとき | 使い道の例 |
|---|---|---|---|---|
PreToolUse |
あり | あり | ツール呼び出しの要求(ブロックや変更ができる) | 危険なシェルコマンドを止める |
PostToolUse |
あり | あり | ツールの実行結果 | ファイル変更を監査記録に残す |
PostToolUseFailure |
あり | あり | ツールの実行の失敗 | ツールのエラーを処理・記録する |
PostToolBatch |
なし | あり | ツール呼び出しのバッチ全体が解決したとき(次のモデル呼び出しの前にバッチごとに1回) | バッチ全体に規約を1回だけ注入する |
UserPromptSubmit |
あり | あり | プロンプトの送信(Claude Code が自分で始めたターンを含む) | プロンプトに文脈を足す |
UserPromptExpansion |
なし | あり | ユーザーが打ったコマンドや MCP プロンプトが、Claude に届く前にプロンプトへ展開されるとき(Claude 自身がスキルを呼ぶときは発火しない) | コマンドの直接呼び出しを止める、スキルを打ったときに文脈を足す |
MessageDisplay |
なし | あり | テキストを含むアシスタントのメッセージが完了したとき(メッセージごとに1回、全文) | トランスクリプトを変えずに、表示するテキストを伏せる・整形する |
Stop |
あり | あり | エージェントの実行の停止 | 終了前にセッションの状態を保存する |
StopFailure |
なし | あり | ターンが通常の停止でなく、API エラーで終わったとき | 失敗を記録する・通知する |
SubagentStart |
あり | あり | サブエージェントの初期化 | 並列タスクの起動を追う |
SubagentStop |
あり | あり | サブエージェントの完了 | 並列タスクの結果を集約する |
PreCompact |
あり | あり | 会話の圧縮の要求 | 要約の前に全文を保存する |
PostCompact |
なし | あり | 会話の圧縮の完了 | 生成された要約を記録する |
PreModelSwitch |
なし | あり | 要求されたモデルの切り替えの前(ブロックできる) | 特定のモデルへの切り替えを止める |
PostModelSwitch |
なし | あり | セッションのモデルが変わったとき(自動のフォールバックを含む) | 新しいモデル向けの指示を Claude に渡す |
PermissionRequest |
あり | あり | ツール呼び出しに権限の判断が要るとき | 独自の権限処理 |
PermissionDenied |
なし | あり | auto モードがツール呼び出しを拒否したとき(分類器の判定のない拒否も含む) | 拒否を記録する、再試行してよいと伝える(判定のない拒否では retry: true は無視される) |
SessionStart |
なし | あり | セッションの初期化 | ログや計測の初期化 |
SessionEnd |
なし | あり | セッションの終了 | 一時リソースの後始末 |
Notification |
あり | あり | エージェントの状態メッセージ | 状態を Slack や PagerDuty に送る |
Setup |
なし | あり | セッションのセットアップ・保守 | 初期化作業の実行 |
TeammateIdle |
なし | あり | チームメイトが待機に入ったとき | 仕事の割り当て直し、通知 |
TaskCreated |
なし | あり | TaskCreate でタスクが作られたとき |
タスクの命名規則を強制する |
TaskCompleted |
なし | あり | タスクが完了にされたとき | テストが通るまでタスクを閉じさせない |
Elicitation |
なし | あり | MCP サーバーが作業中にユーザーの入力を求めたとき | MCP の入力要求にプログラムで答える |
ElicitationResult |
なし | あり | ユーザーが MCP の要求に答えたとき | サーバーに戻る前に応答を変える・止める |
ConfigChange |
なし | あり | 設定ファイルの変更 | 設定を動的に再読み込みする |
InstructionsLoaded |
なし | あり | CLAUDE.md やルールのファイルが文脈に読み込まれたとき |
どの指示ファイルが読まれたかを監査する |
WorktreeCreate |
なし | あり | git の worktree の作成 | 隔離した作業場所を追う |
WorktreeRemove |
なし | あり | git の worktree の削除 | 作業場所のリソースを片づける |
CwdChanged |
なし | あり | セッション中の作業ディレクトリの変更 | ディレクトリごとに環境変数を読み直す |
FileChanged |
なし | あり | 監視中のファイルの変更・作成・削除 | プロジェクトのファイルが変わったら設定を読み直す |
DirectoryAdded |
なし | あり | セッション中に作業ディレクトリが加わったとき | 途中で足したリポジトリの依存を入れる |
フックを設定する#
hooks オプション(Python は辞書、TypeScript はオブジェクト)に、キーをイベント名、値を matcher の配列にして渡します。各 matcher は、省略可能なフィルターのパターンとコールバックを持ちます。
| オプション | 型 | 既定 | 説明 |
|---|---|---|---|
matcher |
string |
undefined |
イベントのフィルター対象に照合するパターン。設定ファイルの matcher の規則に従う。ツールのフックではツール名。MCP ツールは mcp__<server>__<action> の形で、<server> は mcpServers のキー |
hooks |
HookCallback[] |
- | 必須。パターンに一致したとき動くコールバックの配列 |
timeout |
number |
undefined |
タイムアウト(秒)。省略するとイベントの既定のタイムアウトが適用される |
ヒント
可能な限り matcher でツールを絞ります('Bash' は Bash だけ)。省略すると、そのイベントのすべてで動くので、すべてのツール呼び出しを記録したいときだけ、意図して省きます。
matcher が照合する対象は、イベントによって違います(ツール系はツール名、Notification は通知の種類)。規則の細部は フックのリファレンス にあります。
コールバックの入力と出力#
コールバックは3つの引数を受け取ります。
- 入力データ:イベントの詳細を持つ型付きのオブジェクト。
PreToolUseHookInputはtool_nameとtool_input、NotificationHookInputはmessageを持つなど、フックの種類ごとに形が違う。どのフックの入力にもsession_id・cwd・hook_event_nameがある。agent_idとagent_typeは、フックがサブエージェントの中で発火したときに入る(TypeScript は基底の入力にあり全フックで使える。Python はPreToolUse・PostToolUse・PostToolUseFailure・PermissionRequestでは省略可能、SubagentStartとSubagentStopでは必須) - ツール使用 ID(
str | None/string | undefined):同じツール呼び出しのPreToolUseとPostToolUseを結び付ける - コンテキスト:TypeScript は取り消し用の
signal(AbortSignal)を持つ。Python では将来のために予約されている
戻り値のオブジェクトには、2種類のフィールドがあります。
| 種類 | 内容 |
|---|---|
| トップレベルのフィールド | すべてのイベントで受け付ける。systemMessage はユーザーにメッセージを表示する。continue(Python は continue_)は、このフックのあとエージェントが動き続けるかを決める。イベントによっては捨てられるか、別の場所に届く |
hookSpecificOutput |
現在の操作を制御する。中のフィールドはイベントの種類による |
PreToolUseのhookSpecificOutput:permissionDecision("allow"・"deny"・"ask"・"defer")・permissionDecisionReason・updatedInput。"defer"を返すと、そのターンはstop_reasonが"tool_deferred"の結果メッセージで終わり、あとで呼び出しを再開できますPostToolUseのhookSpecificOutput:additionalContextはツール結果に情報を足します。Claude が見る前にツールの出力を置き換えるにはupdatedToolOutputを設定します(どのツールでも、両方の SDK で使える)。古いupdatedMCPToolOutputは MCP ツールの出力だけを置き換え、非推奨です- TypeScript の
PostToolUseはclassifierContextも返せます。auto モードの権限分類器へ向けた、ツール呼び出しの結果についての短いメモです(TypeScript Agent SDK v0.3.236 以降)。コールバックは自分のアプリのプロセスで動くため、メモの中で伝えるユーザーの発言を、分類器がユーザーの意図として扱うことがあります {}を返すと、変更なしで操作を許可します。SDK のコールバックの JSON の出力の形は、Claude Code のシェルコマンド型のフックと同じです
補足
複数のフックや権限ルールが当たるときの優先順位は、deny が defer より、defer が ask より、ask が allow より強いです。どれか1つのフックが deny を返せば、ほかのフックにかかわらず操作はブロックされます。
非同期の出力#
既定では、エージェントはフックが返すまで待ちます。ログやウェブフックの送信のような、エージェントの動きに影響しない副作用だけのフックは、非同期の出力を返して、待たずに進ませられます。
| フィールド | 型 | 説明 |
|---|---|---|
async |
true |
非同期モードを示す。エージェントは待たずに進む。Python は予約語を避けるため async_ を使う |
asyncTimeout |
number |
バックグラウンドの処理のタイムアウト(ミリ秒)。任意 |
非同期の出力は、エージェントがすでに先へ進んでいるので、操作をブロック・変更したり、文脈を注入したりできません。ログ・メトリクス・通知のような副作用にだけ使います。
使い方の例#
// 入力を変更:Write の file_path を /sandbox 以下へ付け替えて自動承認する
const redirect: HookCallback = async (input) => {
const pre = input as PreToolUseHookInput;
const ti = pre.tool_input as { file_path?: string };
return {
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "allow",
updatedInput: { ...ti, file_path: `/sandbox${ti.file_path}` },
},
};
};
updatedInputはpermissionDecision: 'allow'(変更後の入力を自動承認)か'ask'(ユーザーに見せる)と組みます。permissionDecisionを省いても、変更後の入力は適用され、通常の権限評価に流れます。'defer'と組むとupdatedInputは無視されます。元のtool_inputを書き換えず、新しいオブジェクトを返します- 追加の文脈とブロック:
permissionDecision: 'deny'で止め、permissionDecisionReasonでモデルに理由を伝え(再試行を避けさせる)、systemMessageでユーザーに起きたことを見せます - 特定のツールを自動承認:読み取り専用のツール(
Read・Glob・Grep)にpermissionDecision: 'allow'を返すと、確認なしで動き、ほかのツールは通常の権限検査のままです - 複数のフック:イベントが発火すると、一致するフックはすべて並列に動きます。権限の判断は最も厳しい結果が採用され、1つの
denyでツール呼び出しはブロックされます。完了の順序は決まっていないので、各フックは、ほかのフックが先に動いたことに頼らず、独立して書きます - 複数ツールの matcher:
Write|Edit|NotebookEditのようなパイプ区切りの正確な一覧、^mcp__のような正規表現(mcp__で始まる MCP ツールすべて)、省略(名前を問わずすべて)を使い分けます - サブエージェントの追跡:
SubagentStopのフックで、サブエージェントの完了ごとに要約を記録できます - フックからの HTTP 要求:非同期の処理(ウェブフックの送信)もできます。エラーはフックの中で捕まえ、外へ伝えません
- Slack への通知:
Notificationのフックで通知を外部へ転送できます。SDK のセッションで Claude Code がこのフックを動かす通知の種類は、permission_prompt(権限要求がcanUseToolで約6秒待たされたあと。TypeScript Agent SDK v0.3.233 以降、Python Agent SDK v0.2.139 以降)と、ユーザーのプロンプトの割り込みの流れのelicitation_complete・elicitation_responseです。idle_prompt・auth_success・elicitation_dialogなどは、SDK のセッションが動かさない対話 UI から出るので、出ません。通知には人が読めるmessageが付き、titleが付くこともあります
困ったときは#
フックが動かない
- イベント名は大文字小文字を区別します(
PreToolUse。preToolUseではない) - matcher がツール名に完全に一致しているか、
options.hooksの正しいイベントの下にあるか確かめます NotificationやSubagentStopのような matcher を使う非ツールのフックは、別のフィールドに照合します。Stopは matcher を完全に無視します- エージェントが
max_turnsに達すると、フックが動く前にセッションが終わるので、動かないことがあります
matcher が思ったように絞れない
matcher はツール名にだけ照合し、ファイルパスなどの引数には照合しません。ファイルパスで絞るには、フックの中で tool_input.file_path を調べます。
フックのタイムアウト
各コールバックは、HookMatcher の timeout(秒)で決めたタイムアウトで動きます。省略するとイベントの既定です。ほとんどのイベントは600秒、UserPromptSubmit・PreModelSwitch・PostModelSwitch は30秒、MessageDisplay は10秒です。SessionEnd は、シャットダウン中のより短い予算(既定 1.5 秒)で動きます。超えるとコールバックは取り消され、出力は捨てられ、セッションは固まらず続きます。その後はイベントによります。
| イベント | タイムアウトしたとき |
|---|---|
PreToolUse |
ツール呼び出しは実行されず、フックがタイムアウトまでに応答しなかったという結果が Claude に返り、ターンは続く。別の PreToolUse フックが明示の deny を返していれば、代わりにその拒否が返る。v2.1.210 より前は、ユーザーの拒否として報告され、無人のセッションが入力待ちで止まった |
PostToolUse・PostToolUseFailure |
ツール結果は残り、ターンは続く |
UserPromptSubmit・UserPromptExpansion |
フックの名前とタイムアウトを書いたメッセージでプロンプトをブロックし、セッションは続く(政策ゲートになりうるため、タイムアウトしたプロンプトを検査なしで通さない)。v2.1.208 より前は、error_during_execution でクエリが終わった |
Stop・SubagentStop |
判断なしを返したものとして数え、止まる。ほかのフックの判断は有効。Claude Code v2.1.273 より前は、失敗したフックの実行として数え、ほかのフックの判断も捨てていた |
SessionStart |
出力なしとして数え、ほかの SessionStart フックの出力でセッションは続く |
PreModelSwitch |
モデルの切り替えをブロックする(応答しないフックは、切り替えを承認していない) |
Notification・PreCompact・PostModelSwitch などそのほか |
失敗を記録して続ける |
- メインのセッションで
StopやSessionStartのコールバックが初めてタイムアウトすると、アプリが応答しなかったというSDKInformationalMessageがメッセージストリームに入ります。アプリが応答しない間は、以降のタイムアウトでは繰り返されません - コールバックの待機中にクエリを中断すると、Claude Code は待機中のツール呼び出しを取り消します(v2.1.208 より前は、
PreToolUseの待機中に中断しても、ツール呼び出しが進むことがあった) - 時間が足りないなら、
HookMatcherのtimeoutを上げます。TypeScript は、3番目の引数のAbortSignalで、タイムアウトの取り消しをうまく処理できます
ツールが意図せずブロックされる
すべての PreToolUse フックの permissionDecision: 'deny' の返しを調べ、フックにログを足して permissionDecisionReason を見ます。空の matcher はすべてのツールに当たるので、matcher が広すぎないかも確かめます。
変更した入力が適用されない
updatedInputは、トップレベルでなくhookSpecificOutputの中に置きますpermissionDecision: 'defer'と組むと、変更後の入力が落ちます。省略は問題ありません。'allow'(自動承認)か'ask'(ユーザーに見せる)も使えます- どのフックの出力か分かるように、
hookSpecificOutputにhookEventNameを含めます
Python で SessionStart・SessionEnd が使えない
SessionStart と SessionEnd は、TypeScript では SDK のコールバックとして登録できますが、Python の HookEvent 型には無いので使えません。Python では、.claude/settings.json などの設定ファイルに書く、シェルコマンド型のフックとしてだけ使えます。SDK アプリからシェルコマンド型のフックを読み込むには、setting_sources / settingSources に該当のソースを入れます。Python のコールバックで初期化処理をするには、client.receive_response() の最初のメッセージを引き金にします。
サブエージェントの権限確認が増える
複数のサブエージェントを起こすと、それぞれが自分のツール呼び出しの許可を別に求めることがあります。PreToolUse フックで特定のツールを自動承認するか、権限ルール(サブエージェントは親の会話から継承します)を設定します。
サブエージェントでフックが再帰する
サブエージェントを起こす UserPromptSubmit フックは、そのサブエージェントが同じフックを引き起こすと、無限ループになりえます。共有の変数やセッションの状態で、すでにサブエージェントの中かを追う、フックを最上位のエージェントのセッションだけで動かす、で防ぎます。
systemMessage が出力に出ない
systemMessage はモデルでなくユーザーに見せるメッセージです。Claude Code v2.1.227 以降では、フックの systemMessage が SDKInformationalMessage としてメッセージストリームに出ることがあります(イベントによります)。モデルに文脈を渡すには additionalContext を返します。v2.1.227 より前は、SDK がメッセージストリームにフックの出力を出すのは SessionStart と Setup だけで、ほかのイベントでは includeHookEvents(Python は include_hook_events)が足すライフサイクルイベントにだけ出ました。フックの判断をアプリへ確実に出したいなら、別に記録するか、専用の出力経路を使います。
サブエージェント#
サブエージェントは、メインのエージェントが起こす、別のエージェントのインスタンスです。文脈の分離・並列実行・専用の指示を、メインのプロンプトを太らせずに実現します(Claude Code 本体の サブエージェント)。
作り方は3通りです。
- プログラムで:
query()のオプションのagents。SDK のアプリに推奨される方法 - ファイルで:
.claude/agents/のディレクトリのマークダウン - 組み込みの
general-purpose:何も定義しなくても、Claude が Agent ツールでいつでも呼べる
利点は4つです。
- 文脈の分離:各サブエージェントは自分の会話で動き(フォークでなければ新しく始まる)、途中のツール呼び出しと結果はサブエージェントの中に留まり、最後のメッセージだけが親へ返る
- 並列化:複数のサブエージェントが同時に動くので、独立した小作業は、全部の合計でなく、最も遅いものの時間で終わる
- 専用の指示と知識:サブエージェントごとにシステムプロンプトを作り込める
- ツールの制限:サブエージェントは特定のツールに限れる。
doc-reviewerにReadとGrepだけを渡せば、文書を決して変更しない
定義する#
for await (const message of query({
prompt: "認証モジュールのセキュリティ上の問題をレビューして",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-reviewer": {
description: "コードレビューの専門家。品質・セキュリティ・保守性のレビューに使う。",
prompt: "あなたはセキュリティ・性能・ベストプラクティスに詳しいコードレビューの専門家です。...",
tools: ["Read", "Grep", "Glob"], // 読み取り専用
model: "sonnet",
},
"test-runner": {
description: "テストスイートを実行して分析する。",
prompt: "あなたはテスト実行の専門家です。...",
tools: ["Bash", "Read", "Grep"],
},
},
},
})) { /* ... */ }
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"],
agents={
"code-reviewer": AgentDefinition(
description="コードレビューの専門家。品質・セキュリティ・保守性のレビューに使う。",
prompt="あなたはセキュリティ・性能・ベストプラクティスに詳しいコードレビューの専門家です。...",
tools=["Read", "Grep", "Glob"],
model="sonnet",
),
},
)
AgentDefinition のフィールド#
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
description |
string |
はい | このエージェントをいつ使うかの自然言語の説明 |
prompt |
string |
はい | 役割と動きを決める、エージェントのシステムプロンプト |
tools |
string[] |
いいえ | 許可するツール名の配列。省略すると、サブエージェントが使えるすべてのツールを継承する |
disallowedTools |
string[] |
いいえ | エージェントのツールから外すツール名。MCP サーバー単位のパターンも使える(mcp__server か mcp__server__* はそのサーバーの全ツール、mcp__* はすべての MCP ツール) |
model |
string |
いいえ | このエージェントのモデルの上書き。'fable'・'opus'・'sonnet'・'haiku'・'inherit' のエイリアスか完全なモデル ID。'inherit' はメインのモデルを使う。省略すると Claude Code がサブエージェントのモデルの順で選ぶ |
skills |
string[] |
いいえ | 起動時に文脈へ先読みするスキル名。列挙しないスキルも Skill ツールで呼べる |
memory |
'user' | 'project' | 'local' |
いいえ | このエージェントのメモリの出どころ |
mcpServers |
(string | object)[] |
いいえ | このエージェントで使える MCP サーバー。名前かインラインの設定 |
initialPrompt |
string |
いいえ | このエージェントがメインスレッドのエージェントとして動くとき、最初のユーザーターンとして自動で送られる。サブエージェントとして呼ばれたときは無視される |
maxTurns |
number |
いいえ | エージェントが止まるまでのターン数の上限。上限に達すると、Claude Code は出力に部分的と印を付けて返し、エージェントを再開して続けられる(部分的の印は Claude Code v2.1.246 以降) |
background |
boolean |
いいえ | 呼ばれたとき、止まらないバックグラウンドのタスクとして動かす |
omitClaudeMd |
boolean |
いいえ | サブエージェントとして動くとき、user・project・local の CLAUDE.md を読まずに動かす(管理ポリシーのファイルは読み込まれる)。メインスレッドのエージェントのときは無視される。TypeScript Agent SDK v0.3.271 以降が必要で、Python の AgentDefinition にはこのフィールドがない |
effort |
'low' | 'medium' | 'high' | 'xhigh' | 'max' | number |
いいえ | このエージェントの推論の労力 |
permissionMode |
PermissionMode |
いいえ | このエージェント内のツール実行の権限モード。適用されるかは、サブエージェントの継承の規則で決まる |
- Python の
AgentDefinitionでも、disallowedToolsやmcpServersのような複数語のフィールド名は、通信の形に合わせて camelCase のままです - サブエージェントは、既定でバックグラウンドで動きます。
run_in_backgroundを省いた Agent ツール呼び出しは、バックグラウンドのサブエージェントを起こし、結果が要るときは Claude がrun_in_background: falseを設定します。特定のエージェントを、Claude の要求にかかわらずバックグラウンドで動かすにはbackgroundをtrueにします(Claude Code v2.1.198 より前は、バックグラウンドの既定が段階的に展開中で、run_in_backgroundを省いた呼び出しが同期で動くことがあった) - サブエージェントも、自分のサブエージェントを起こせます
- プログラムで定義したエージェントは、同名のファイルベースのエージェントより優先されます
subagent_typeなしで Agent ツールを呼ぶと、組み込みのgeneral-purposeサブエージェントになります。CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS=1でこの既定を外せます(そのときの呼び出しはsubagent_type is requiredで失敗します)
サブエージェントが受け取るもの#
フォークでなければ、サブエージェントの文脈は空ではないが新しく始まり、親の会話はありません。親から渡る内容は Agent ツールの prompt の文字列だけなので、必要なファイルパス・エラーメッセージ・判断は、その中に書きます。
| 受け取る | 受け取らない |
|---|---|
自分のシステムプロンプト(AgentDefinition.prompt)と Agent ツールのプロンプト |
親の会話履歴とツール結果 |
プロジェクトの CLAUDE.md(settingSources 経由)。omitClaudeMd を設定したエージェントを除く |
AgentDefinition.skills に列挙しない、先読みされるスキルの内容 |
ツール定義(親から継承するか、tools の部分集合。バックグラウンドの実行では絞られる) |
親のシステムプロンプト |
SendMessageツールを持つサブエージェントは、セッションで動いているほかの名前付きエージェントの一覧を、最初のターンに自動で受け取ります(フォークは、親の会話を継承するので受け取らない)- サブエージェントは、メインのセッションの拡張思考の設定を継承します
- 親はサブエージェントの最終の報告を受け取りますが、自分の応答で要約することがあります。ユーザー向けの応答にそのまま残させたいなら、メインの
query()のプロンプトかsystemPromptにそう指示します - v2.1.210 以降では、Claude Code は、親が読む前に最後のメッセージを、指示の形のパターンについて走査します。制御タグの模倣(
<system-reminder>のようなハーネスだけが出すタグ)は、開き山括弧の後ろにバックスラッシュを入れて無害化し、何も削りません。権限設定への言及(.claude/settings.json・bypassPermissions・--dangerously-skip-permissions)はそのまま残します。Human:やAssistant:で始まる行は、コロンの前にバックスラッシュを入れて、会話のターンの境界を真似られないようにします。制御タグか権限設定に一致したときは、一致したパターンを示す[harness: ...]の行が先頭に付きます(ターンの印だけの一致では付かない)。この走査は、サブエージェントのテキストを取り除いたり言い換えたりしません - サブエージェントを早く終わらせる API エラー(レート制限など)は、結果としては届きません
呼び出す#
- 自動:Claude が、作業とサブエージェントの
descriptionから呼ぶかを決めます。説明は、明確で具体的に書きます - 明示:プロンプトで名前を挙げると確実に呼ばれます(自動のマッチングを経ません)
- 動的:実行時の条件でエージェントの定義を作れます(厳しさに応じて、厳格なレビューにはより高性能なモデルを使うなど)
呼び出しの検出は、tool_use ブロックの name が "Agent" のものを見ます。サブエージェントの文脈の中のメッセージには parent_tool_use_id が付きます。
補足
ツールは tool_use ブロックでは "Agent"、system:init のツール一覧では "Task" と出ます。Claude Code v2.1.63 より前は、tool_use ブロックも "Task" でした。SDK の版をまたいで検出するには、block.name の両方に一致させます。メッセージの構造は、Python は message.content、TypeScript は message.message.content です。
サブエージェントを再開する#
再開したサブエージェントは、これまでのツール呼び出し・結果・推論を含む会話履歴をすべて保持します。maxTurns で止まったときは、Agent ツールの結果の出力に部分的と印が付きます。完了すると、Agent ツールの結果のテキストに agentId: <id> が入ります。組み込みの Explore と Plan は1回きりで agentId を返さないので、再開が要るなら、カスタムのエージェントか general-purpose を使います。
- セッション ID を控える:最初のクエリのメッセージから
session_idを取り出す - エージェント ID を取り出す:Agent ツールの結果のテキストから
agentIdを読む - セッションを再開する:2回目のクエリのオプションに
resume: sessionIdを渡し、プロンプトにエージェント ID を含める。query()は既定で新しいセッションを始めるので、サブエージェントのトランスクリプトに触れるには同じセッションを再開する
カスタムのエージェントなら、2回のクエリの agents に同じ定義を渡します。サブエージェントのトランスクリプトは別のファイルに保存され、メインの会話とは別に残ります(圧縮の扱いと cleanupPeriodDays は Claude Code 本体のサブエージェントの文書)。
ツールの制限#
tools を省くと、サブエージェントが使えるすべてのツールを得ます。列挙すると、そのツールだけです。外したツールはセッションにないので、Claude はそれなしで動きます(権限の確認もエラーも出ません)。
| 用途 | ツール | 説明 |
|---|---|---|
| 読み取り専用の分析 | Read、Grep、Glob |
コードを調べられるが、変更も実行もできない |
| テストの実行 | Bash、Read、Grep |
コマンドを実行して出力を分析できる |
| コードの変更 | Read、Edit、Write、Grep、Glob |
コマンドの実行なしに、読み書きがすべてできる |
| フルアクセス | 全ツール | tools を省いて、サブエージェントが使えるツールを継承する |
深さ・同時実行数・費用の上限#
補足
この節は、TypeScript SDK v0.3.219 と Python SDK v0.2.127 以降(Claude Code v2.1.219 以降を同梱する版)の動きです。それより前は、一部の上限が無いか、既定が違うので、上限に頼る前に更新します。
Claude は、サブエージェントをいつ・何個起こすかを自分で決めます。各サブエージェントは自分の API リクエストを出し、それはクエリの total_cost_usd に数えられ、さらにサブエージェントがサブエージェントを起こせるので、1つのプロンプトがエージェントの木に育つことがあります。深さ・同時実行数は環境変数を env で、費用はクエリのオプションで制限します。
| 上限 | 設定 | 既定 | 上限に達したときの Claude Code |
|---|---|---|---|
| 深さ | CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH |
メインのエージェントの下に 3 層。1 なら、サブエージェントはさらにサブエージェントを起こせない |
最下層のサブエージェントは起こせなくなり、任された仕事を自分でやる |
| 同時実行数 | CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS |
同時に 20(Agent ツールで起こしたすべてのサブエージェントを数える) |
動いている数が上限を下回るまで、Concurrent subagent limit reached を返して、新たに起こすことを拒む。ultracode が有効なセッションは拒まれない |
| 費用 | TypeScript は maxBudgetUsd、Python は max_budget_usd |
上限なし(呼び出し自身の費用を数え、サブエージェントのリクエストも含む) | 3通りで強制する:新たに起こすことを Budget limit reached で拒む、動いているバックグラウンドのサブエージェントを止める、クエリを結果の subtype error_max_budget_usd で終える |
TypeScript は env でサブプロセスの環境を置き換えるので、PATH などを残すには process.env を展開します。Python は継承した環境に重ねます。
options: {
maxBudgetUsd: 5,
env: {
...process.env,
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH: "1",
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS: "5",
},
}
上限に達したときの見え方です。
- 費用の上限の下:
successと見積もりの費用が見える - 費用の上限:費用が
5以上のerror_max_budget_usdが見え、そのあとエラーのハンドラーが動く - 同時実行数の上限:メッセージストリームに、
Concurrent subagent limit reachedを持つtool_resultブロックが見える(Claude にも同じブロックが Agent ツールの結果として届く)
Claude Opus 5 は、前のモデルよりサブエージェントへ任せやすいので、上の3つの上限は Opus 5 を動かすクエリで特に効きます。Claude Code が自前の指示を足すかは、使うシステムプロンプトで決まります。
claude_codeプリセット:モデルが Opus 5 のとき、頼まれない限り Agent ツールを呼ばないよう Claude に伝える1行をシステムプロンプトへ足す(Agent ツールは使えるまま)- 自前のプロンプト、または
systemPromptなし:Claude Code がシステムプロンプトを作らないので、その行はない。Opus 5 の prompting guide にある委任の指示を、自分のプロンプトへ足す
どちらの指示も Claude を誘導するだけなので、上限も併せて設定します。上限は、Claude がどう任せようと Claude Code が強制します。
ワークフローで拡大する#
サブエージェントは、1ターンに少数の仕事を任せるのに向きます。数十〜数百のエージェントを調整する実行には、オーケストレーションを会話の外でランタイムが実行するスクリプトへ移す Workflow ツールを使います(違いは ワークフロー)。Workflow ツールは TypeScript Agent SDK v0.3.149 以降で使え、allowedTools に Workflow を入れるとワークフローの実行が自動承認されます。
トラブルシューティング#
| 症状 | 対処 |
|---|---|
| Claude がサブエージェントに任せず自分でやる | プロンプトでサブエージェントを名前で挙げる(「code-reviewer エージェントで認証モジュールを確認して」)。description に、いつ使うかを明確に書く |
| ファイルベースのエージェントが読み込まれない | 下の表を見る |
Claude Code は ~/.claude/agents/ と .claude/agents/ を監視し、新規や編集したエージェントのファイルを数秒で拾います(再起動は要りません)。定義が現れないときの原因です。
- 新しい
agentsディレクトリ:監視はセッション開始時に存在したディレクトリだけが対象です。新しいディレクトリの最初のファイルには、セッションの再起動が要ります(最も多い原因) - 無効な frontmatter、または
nameの重複:ファイルの YAML と、既存のエージェントが同じnameを使っていないかを確かめます --disable-slash-commands:このフラグで始めたセッションは、ディレクトリを監視せず、新しいファイルの読み込みに常に再起動が要ります- 追加したディレクトリのファイル:
add_dirs(Python)・additionalDirectories(TypeScript)・CLI の--add-dirや/add-dirで追加したディレクトリの.claude/agents/は読み込まれますが、監視されません。新規や編集したファイルには、セッションの再起動が要ります - 同名のプログラムのエージェント:
query()に渡したagentsが、同名のファイルベースのエージェントを上書きします
スキル#
スキルは、SKILL.md に指示・説明・補助資料をまとめたもので、関係するときに Claude が呼びます(Claude Code 本体の使い方は スキル)。
- ファイルシステムの成果物として定義する:
.claude/skills/<name>/SKILL.mdのように、1つのスキルを1つのディレクトリに作る - ファイルシステムから読み込む:
settingSources(Python はsetting_sources)で決まる場所から読む - 自動で見つかる:ファイルシステムの設定が読み込まれると、SDK は user と project のディレクトリからスキルのメタデータを起動時に見つけ、Claude が呼んだときに全内容を読み込む
- モデルが呼ぶ:Claude が文脈から自分で使うかを決める
- ユーザーが呼ぶ:プロンプトに
/<name>を送って直接呼ぶ skillsオプションで範囲を決める:見つかったスキルは既定で有効。スキル名のリスト・"all"・[]で、Claude が呼べるものを決める
サブエージェントとは違い、スキルをプログラムで登録する API はありません。
既定の query() では user と project のソースを読み込むので、~/.claude/skills/・<cwd>/.claude/skills/・リポジトリのルートまでの親ディレクトリの .claude/skills/ が使えます。project のソースは、additionalDirectories(Python は add_dirs)で渡す各ディレクトリの <dir>/.claude/skills/ も含みます。settingSources を明示するなら、プロジェクトと追加ディレクトリのスキルを残すために 'project' を、個人のスキルを残すために 'user' を含めます。特定のパスから読み込むには、plugins オプションを使います。
スキルを使う#
skills を設定すると、SDK が Skill ツールを allowedTools に自動で足します。tools を明示するなら、"Skill" を含めます。
for await (const message of query({
prompt: "チームのコードレビューのチェックリストでこの PR をレビューして",
options: {
cwd: process.cwd(),
settingSources: ["user", "project"],
skills: ["code-review", "security-check"], // これらだけ。全部なら "all"
allowedTools: ["Read", "Grep", "Glob"],
},
})) { /* ... */ }
options = ClaudeAgentOptions(
setting_sources=["user", "project"],
skills="all",
allowed_tools=["Read", "Grep", "Glob"],
)
- 読み込みの確認:ストリームの初めの
initのsystemメッセージのskills配列を見ます。descriptionかwhen_to_useの frontmatter を持つ、ユーザーが呼べるスキルと、Claude Code に同梱のスキルが並びます。user-invocable: falseのスキルは、読み込まれて Claude が使えますが、配列には出ません。配列は、skillsのリストに入っているかにかかわらず、同じスキルを並べます - 名前で絞る:
skillsのリストには、SKILL.mdのnameかスキルのディレクトリ名と、プラグインのスキルはplugin:skillの形で書きます。リストは完全一致の名前だけを取り、完全な名前として使えない項目があると、query()はセッションの開始前にリストを拒否します。モデルにはリストにないスキルが見えず、Skill ツールも拒否しますが、ファイルはディスクに残り、ReadとBashからは届きます。リストで絞っても、名前による呼び出し(下記)は制限されません。全部を呼べるようにするなら、ワイルドカードでなくskills: "all"を渡します
SDK のセッションのコマンド#
コマンドは、プロンプトに /<name> を送って実行するものすべてです。
| 種類 | 内容 |
|---|---|
| 組み込みコマンド | SDK が動かす Claude Code のプロセスにコードされた処理(例:/compact) |
| 同梱のスキル | Claude Code に含まれるプロンプトの成果物(例:/code-review) |
| 自分のスキル | 自分で書いたスキル。ユーザーが呼べるスキルの名前は自動でコマンドの一覧に加わり、自作の /security-check を呼ぶことと組み込みを呼ぶことは同じ |
| カスタムコマンドのファイル | 古い形。.claude/commands/ の平らなマークダウンで、ファイル名がコマンド名になる。後継はスキル |
既定では、ユーザーも Claude も、どのスキルも呼べます。どちらの経路も、スキルの frontmatter で制限できます(コマンド一覧)。
- 使えるコマンドの確認:
system/initメッセージのslash_commandsフィールドが一覧です。対話的な端末が要るコマンド(/theme・/terminal-setup)は載りません。user-invocable: falseのスキルも載りません。MCP サーバーを設定したセッションは、MCP のプロンプトもコマンドとして出せます - 名前で呼ぶ:コマンドをプロンプトの文字列に含めて送ります。呼び出しは
skillsオプションに依存しません。skillsのリストに無くても、/<name>でユーザーが呼べるスキルは動きます。/compactのように会話履歴に作用するコマンドは、先にメッセージが要ります - セッションにも組み込みコマンドにも無い
/<name>は、クエリを失敗させません。Claude Code は、コマンドが動かなかったという注記付きで、プロンプトを普通のメッセージとして Claude に送ります。モデルの1ターンを使い、Claude の返事が返ります(v2.1.274 より前は、Unknown command: /<name>を結果として、モデルのターンなしで返した) - セッションで使えない組み込みコマンド(
/themeなど)は、/theme isn't available in this environment.を結果として、モデルのターンなしで返します - コマンドも、ほかのプロンプトと同じく
maxTurnsに達し、successでなくエラーの結果で終わることがあります。ループをtry/catch(Python はtry/except)で囲むか、maxTurnsを十分に高くします
/compact は、古いメッセージを要約して会話履歴を小さくします。要約するだけのメッセージが要るので、単発の新しい query()(空の文脈で始まる)では使えず、ストリーミング入力か、セッションの再開のように、前のターンがある場面で使います。圧縮が動くと compact_boundary の system メッセージが届きます。続けたセッションにメッセージはあっても /compact が要約できるものがないときは、エラーにならず success の結果で終わり、compact_boundary は来ません。結果のテキストが理由を持ちます(たとえば、セッションにプロンプトはあるが Claude の返信がまだないときの Not enough messages to compact.)。
/clear は、会話を空の文脈に戻し、以降のプロンプトは会話履歴なしで始まります。以前の会話はディスクに残り、セッション ID を resume に渡して戻れます。ストリーミング入力で、1つの接続に複数のプロンプトを送るときに役立ちます。単発の query() は毎回空の文脈で始まるので、/clear に実質の効果はなく、新しい query() を始めます。
スキルを作る#
SKILL.md を含むディレクトリを作り、YAML の frontmatter とマークダウンの本文を書きます。description が、Claude がそのスキルを呼ぶ場面を決めます。
.claude/skills/security-check/
└── SKILL.md
---
name: security-check
description: Run a security vulnerability scan
---
Analyze the codebase for security vulnerabilities including:
- SQL injection risks
- XSS vulnerabilities
- Exposed credentials
- Insecure configurations
置き場所は、主な2つのレベルです。
- プロジェクトのスキル:
.claude/skills/。そのプロジェクトだけで使える - 個人のスキル:
~/.claude/skills/。すべてのプロジェクトで使える
.claude/commands/ の既存のカスタムコマンドのファイルは、そのまま動きます。.claude/commands/deploy.md は /deploy を作り、.claude/skills/deploy/SKILL.md のスキルと同じように動きます(同名のときにどちらが動くかは スキル)。SDK は、.claude/commands/ と ~/.claude/commands/ を、スキルと同じ2つのスコープから読み込みます。ファイルを置いたら、Claude は説明に当てはまる依頼でスキルを呼び、ユーザーは /security-check と送って直接呼べます。スキルの名前は、init メッセージの slash_commands にも入ります。
補足
Claude Code には、同梱の code-review と verify のスキルがあります。同梱のスキルと同じ名前の .claude/commands/ のファイル(.claude/commands/code-review.md など)を作ると、そのコマンドが同梱のスキルを隠し、slash_commands には名前が1回だけ載ります。
スキルのツールを事前に承認する#
SDK のセッションでは、プロジェクトと個人のスキルのツールを、スキルの allowed-tools の frontmatter か、クエリの設定の allowedTools(Python は allowed_tools)で事前に承認できます。組織が管理設定で allowManagedPermissionRulesOnly を設定していると、Claude Code はどちらも無視します。claude.ai から同期したスキルは、それ自身の frontmatter の規則に従います。
スキルはセッションのツールで動きます。Read・Grep・Glob を allowedTools で事前に承認すれば、スキルの実行中に Claude が、承認で止まらずにファイルを調べられます。この一覧は、名前を挙げたツールを事前に承認するもので、ほかを制限するものではありません。
トラブルシューティング#
| 症状 | 確認すること |
|---|---|
| スキルが見つからない | settingSources / setting_sources を明示して user と project を省いていないか(省くとスキルは読み込まれない)。cwd が、.claude/skills/ を含むディレクトリ(同じリポジトリの中)以下か。ファイルの場所は .claude/skills/<name>/SKILL.md か |
| スキルが使われない | skills のリストにスキル名があるか。リストにないスキルを Claude が呼ぼうとすると、Skill ツールが Skill <name> is not in this session's skills allowlist を返す。名前を足すか、プロンプトに /<name> を送って直接呼ぶ(リストに載せなくても動く)。description が具体的で、関連する語を含むか |
Invalid skill name |
skills のリストの名前が、完全なスキル名として使えない |
skills のリストの名前が完全なスキル名として使えないと、query() は Claude Code のプロセスを始める前にリストを拒否します。拒否される名前は次のとおりです。
- 空の名前
- かっこ・カンマ・制御文字を含む名前
- 前後に空白が付いた名前
- 単独の
*や:*の接尾辞のようなワイルドカードの形
TypeScript SDK は、破った規則を述べた Error を投げます(skills: ["docs:*"] が一例)。空の名前では Skill names must be non-empty strings. です(TypeScript Agent SDK 0.3.221 より前は、この検査がなかった)。Python SDK は ValueError を送出します(Python Agent SDK 0.2.129 より前は、この検査がなかった)。YAML の構文エラーなどの一般的なスキルのトラブルは、Claude Code 本体のスキルのトラブルシューティングを見ます。
プラグイン#
プラグインは、スキル・エージェント・フック・MCP サーバーをまとめて、プロジェクト間で共有できる拡張です。SDK では、ローカルのディレクトリからプログラムで読み込みます(作り方と配り方は プラグインを作って配る、仕様は プラグインのリファレンス、使い方は プラグインを使う)。
| プラグインの中身 | 内容 |
|---|---|
| スキル | 関係するとき Claude が自分で呼ぶ。/plugin-name:skill-name で直接呼ぶこともできる |
| エージェント | 特定の仕事のための専用サブエージェント |
| フック | ツールの使用などのイベントに応えるハンドラー |
| MCP サーバー | MCP 経由の外部ツールの連携 |
読み込む#
オプションの plugins に、ローカルのファイルシステムのパスを指定します。type は "local" だけを受け付けます。複数の場所のプラグインを読み込めます。マーケットプレイスやリモートのリポジトリで配られているプラグインは、先にダウンロードして、ローカルのディレクトリのパスを渡します。
for await (const message of query({
prompt: "Hello",
options: {
plugins: [
{ type: "local", path: "./my-plugin" },
{ type: "local", path: "/absolute/path/to/another-plugin" },
],
},
})) { /* ... */ }
options = ClaudeAgentOptions(
plugins=[
{"type": "local", "path": "./my-plugin"},
{"type": "local", "path": "/absolute/path/to/another-plugin"},
]
)
- 相対パスは
cwdオプションを基準に解決されます(例:"./plugins/my-plugin")。絶対パスはそのファイルシステムのパスです - パスは、プラグインのルートのディレクトリ(
skills/・agents/・hooks/・commands/・.claude-plugin/の親)を指します - SDK は
~/pluginsのようなチルダを展開しません。パスが存在しないと、SDK はそのプラグインを飛ばしてセッションを続けるので、init メッセージのpluginsのリストで読み込まれたかを確かめます - CLI(
/plugin install my-plugin@marketplace)で入れたプラグインも、インストール先のパスを渡せば SDK で使えます。CLI で入れたものは~/.claude/plugins/を見ます
確認と使い方#
読み込みに成功すると、システムの初期化メッセージに現れます。plugins に名前とパス、skills に名前空間付きのスキル(例:my-plugin:greet)、slash_commands に同じ接頭辞のコマンドが入ります。
プラグインのスキルには、名前の衝突を避けるため、プラグインの名前が自動で付きます。直接呼ぶには、/plugin-name:skill-name をプロンプトとして送ります。
プラグインの構造#
プラグインのディレクトリは、通常 .claude-plugin/plugin.json のマニフェストを持ちます。マニフェストは任意で、なければ Claude Code がディレクトリの構成から部品を自動で見つけます。
my-plugin/
├── .claude-plugin/
│ └── plugin.json # マニフェスト(任意)
├── skills/ # Agent Skills
│ └── my-skill/
│ └── SKILL.md
├── commands/ # 平らな .md のスキル
│ └── custom-cmd.md
├── agents/ # カスタムエージェント
│ └── specialist.md
├── hooks/ # イベントハンドラー
│ └── hooks.json
└── .mcp.json # MCP サーバーの定義
commands/ は、平らなマークダウンのスキルを置く場所です。新しいプラグインでは skills/ を使います(どちらも使えます)。
トラブルシューティング#
プラグインが init メッセージの plugins のリストに出ないときは、同じメッセージの plugin_errors に理由があります。そのうえで次を確かめます。
- パス:プラグインのルート(
skills/・agents/・hooks/・commands/・.claude-plugin/の親)を指しているか plugin.json:マニフェストがあるなら、JSON の構文が正しいか- ファイルの権限:プラグインのディレクトリを読めるか
- ディレクトリの存在:存在しないパスは SDK に飛ばされ、プラグインは
pluginsのリストに現れない
スキルが現れないときは、/plugin-name:skill-name と名前空間付きで呼んでいるか、skills のリストに正しい名前空間で現れているか、各スキルが skills/ の下の自分のサブディレクトリに SKILL.md(例:skills/my-skill/SKILL.md)を持つかを確かめます。
システムプロンプト#
システムプロンプトは、Claude の動き・能力・応答のスタイルを決めます。人が見守って舵を取る CLI や IDE のようなコーディングツールは、claude_code プリセットから始めます。別の画面・別の役割・別の権限モデルを持つエージェントは、自前のプロンプトを書きます(CLI 側の考え方は 出力スタイル と CLAUDE.md とメモリ)。
出発点は3つ#
- 最小の既定:
systemPrompt(Python はsystem_prompt)を指定しないと、SDK は、ツール呼び出しだけを扱う最小のプロンプトを使います。claude_codeプリセットの、セキュリティと安全の指示を含むそのほかの内容は含みません。これは、既定で Claude Code のシステムプロンプトを使うclaude -pとは違います。CLI から移ってきて同じ動きにしたいなら、claude_codeプリセットを指定します claude_codeプリセット:Claude Code の CLI が使うシステムプロンプトで、ツールの使い方とセキュリティ・安全の指示を含みます。systemPrompt: { type: "preset", preset: "claude_code" }(Python はsystem_prompt={"type": "preset", "preset": "claude_code"})で指定し、appendで自分の指示を末尾に足せます- 自前の文字列:自分で書くプロンプト。SDK は渡したものだけを送ります
| 作るもの | 使うもの | 得られるもの |
|---|---|---|
| 人が見守って舵を取る CLI や IDE のようなコーディングツールで、Claude Code の既定でよい | claude_code プリセット |
ツールの案内と安全の規則を含む Claude Code のプロンプト |
| 同じ種類のツールに、コーディング規約・出力形式・領域の文脈のような製品固有の規則を足す | append 付きの claude_code プリセット |
上のすべてに、プリセットのあとへ自分の指示を足したもの。何も取り除かないので、最も危険の少ない調整 |
| 別の画面・役割・権限モデルのエージェントや、コーディング以外のエージェント | 自前のプロンプトの文字列 | 自分が書いたものだけ。エージェントがなお必要とするツールの案内と安全の指示の置き換えは自分の責任 |
| エージェントの人格がなく、すべての動きをユーザーのプロンプトで与える、薄いツール呼び出しのループ | systemPrompt なし |
最小の既定。ツール呼び出しの支えだけ |
「Claude Code と違う」とは、たいてい次のいずれかです。
- 別の画面:出力を、きっかけを作った人が端末で読まない(チャット UI・構造化出力を受けるもの・コーディング以外の自動化)。人の手を介さないコーディングの自動化(lint を直す CI や diff のレビュー)は、作業自体がプリセットの想定なので、プリセットで足ります
- 別の役割:エージェントが自分を Claude Code として名乗るべきでない(サポート用のボット・データ分析のアシスタントなど)
- 別の権限モデル:1歩ごとに人が承認せずに自律して動く、または狭い範囲のリソースに限って動く。Claude Code のプロンプトは、人が関わり、フルのツール群を使えることを想定しています
- コーディング以外の作業:Claude Code のプロンプトの大半はコーディングの指針なので、調査・コンテンツ・運用のエージェントでは、必要な指示と競合します
動きを変える4つの方法#
| 項目 | CLAUDE.md | 出力スタイル | systemPrompt と append |
自前の systemPrompt |
|---|---|---|---|---|
| 永続性 | プロジェクトごとのファイル | ファイルとして保存 | セッションのみ | セッションのみ |
| 再利用 | プロジェクトごと | プロジェクトをまたぐ | コードの複製 | コードの複製 |
| 管理 | ファイルシステム上 | CLI とファイル | コードの中 | コードの中 |
| 既定のツール | 保たれる | 保たれる | 保たれる | 失われる(含めない限り) |
| 組み込みの安全策 | 保たれる | 保たれる | 保たれる | 自分で足す必要がある |
| 調整の度合い | 追加のみ | 既定の置き換えか拡張 | 追加のみ | 完全な制御 |
| バージョン管理 | プロジェクトと一緒 | できる | コードと一緒 | コードと一緒 |
| 範囲 | プロジェクト固有 | ユーザーかプロジェクト | コードのセッション | コードのセッション |
「append 付き」とは、systemPrompt: { type: "preset", preset: "claude_code", append: "..." }(Python は system_prompt={"type": "preset", "preset": "claude_code", "append": "..."})のことです。CLAUDE.md はシステムプロンプトそのものを変えず、SDK が内容を会話にプロジェクトの文脈として注入します。4つの方法は組み合わせられます。
CLAUDE.md#
CLAUDE.md は、プロジェクトの永続的な文脈と指示を Claude に与えます。SDK は内容を会話に注入し、システムプロンプトには手を付けないので、どのシステムプロンプトの設定とも併用できます。
- 対応する設定ソースが有効なときに読み込みます。
'project'は作業ディレクトリのCLAUDE.mdか.claude/CLAUDE.md、'user'は~/.claude/CLAUDE.mdです - 既定の
query()では両方が有効なので、自動で読み込まれます。settingSourcesを明示するなら、必要なソースを含めます - 読み込みは設定ソースが決めます。
claude_codeプリセットではありません。settingSourcesに空の配列を渡すと読み込まれません - 同じプロジェクトのすべてのセッションで永続し、git でチームと共有でき、コードを変えずに自動で見つかります
出力スタイル#
出力スタイルは、Claude の役割・口調・出力の形式を変える、保存した指示の集まりです。マークダウンのファイルとして置き、セッションとプロジェクトをまたいで再利用できます。frontmatter にメタデータを書き、そのあとにプロンプトの内容を書きます。ユーザー単位なら ~/.claude/output-styles/、リポジトリでチームと共有するなら .claude/output-styles/ に保存します。
- カスタムの出力スタイルは、
claude_codeプリセットのソフトウェアエンジニアリングの指示を外し、自分の指示を使います。残して上に重ねるには、frontmatter にkeep-coding-instructions: trueを書きます。その指示は Claude Code の完全なシステムプロンプトにだけあるので、短いシステムプロンプトのセッションでは効きません(CLAUDE_CODE_SIMPLE_SYSTEM_PROMPTでオンかオフに固定できる)。エージェントがなおソフトウェアの作業をするなら残し、役割を丸ごと置き換えるなら外します - 有効にする方法:CLI の
/output-style <style>(例:/output-style concise)か/configでの選択(/output-styleは Claude Code v2.1.269 以降が必要)。.claude/settings.local.jsonのoutputStyle。TypeScript SDK は、query()に渡すインラインのsettingsオブジェクトの中のoutputStyle、またはoutputStyleを設定した設定ファイルをsettingsで指す(outputStyleはOptionsのトップレベルのフィールドではない)。Python SDK はsettingsオプションに'{"outputStyle": "Explanatory"}'のような JSON 文字列か、設定ファイルのパスを渡す - 出力スタイルは、
settingSourcesに'user'か'project'を含めると読み込まれます
claude_code プリセットに append する#
claude_code プリセットに append を付けると、組み込みの機能を保ったまま、自分の指示を足せます。
options: {
systemPrompt: {
type: "preset",
preset: "claude_code",
append: "コードを書くときは必ずコメントを丁寧に付けること。",
},
}
options = ClaudeAgentOptions(
system_prompt={
"type": "preset",
"preset": "claude_code",
"append": "コードを書くときは必ずコメントを丁寧に付けること。",
}
)
プロンプトキャッシュを、ユーザーとマシンをまたいで効かせる。 既定では、同じ claude_code プリセットと同じ append のテキストを使う2つのセッションでも、自動メモリの場所が違うとプロンプトキャッシュを共有できません。プリセットがその場所を、append のテキストの前のシステムプロンプトに埋め込むためです。場所は、リポジトリのディスク上のパスにちなむ名前で、~/.claude/projects/ の下の絶対パスが既定なので、ユーザー・マシン・チェックアウトごとに違います。CLAUDE.md の内容と、作業ディレクトリ・プラットフォーム・シェル・OS のバージョンのような環境の情報は、会話の中で届くので、システムプロンプトのキャッシュに影響しません。
- システムプロンプトをセッション間で同一にするには、TypeScript は
excludeDynamicSections: true、Python は"exclude_dynamic_sections": Trueを設定します。ユーザーごとの文脈は最初のユーザーメッセージに移り、静的なプリセットとappendのテキストだけがシステムプロンプトに残るので、同じ構成はユーザーとマシンをまたいでキャッシュを共有します - 要件は、
@anthropic-ai/claude-agent-sdkv0.2.98 以降、Python はclaude-agent-sdkv0.1.58 以降です。プリセットのオブジェクトの形にだけ設定します。プリセットでなく自前のプロンプトを渡すと、SDK は無視します - トレードオフ:システムプロンプトから動いたテキストは、Claude には届きますが、ユーザーメッセージの中です。そのテキストは少なくとも自動メモリのディレクトリの場所で、自動メモリの節の全体のことも多いです。ユーザーメッセージの指示は、システムプロンプトの同じテキストよりわずかに重みが小さいので、Claude が自動メモリの指針を一貫して守る度合いが下がることがあります。セッションをまたぐキャッシュの再利用が、それより大事なときに有効にします
- CLI の非対話モードの同等のフラグは
--exclude-dynamic-system-prompt-sectionsです(CLI のコマンドとフラグ)
自前のシステムプロンプト#
systemPrompt に自前の文字列を渡すと、既定を丸ごと置き換えます。
- Python では、大きな自前のプロンプトは、文字列でなく
system_prompt={"type": "file", "path": "..."}でファイルから読み込みます。Python SDK は、文字列のプロンプトを CLI のサブプロセスへ1つのコマンドライン引数として渡すので、OS の引数の長さの上限を超えると、API リクエストの前に、プロセスの起動時に失敗します(Linux ではArgument list too long。しきい値と Windows の動きはSystemPromptFile) - 静的な部分のキャッシュ(TypeScript):自前のプロンプトを、1つの文字列でなく文字列の配列で渡し、静的な部分とそれ以降の間に
SYSTEM_PROMPT_DYNAMIC_BOUNDARYを置けます。毎回同じ指示と、リクエストごとに変わる文脈(担当している顧客やチケットなど)を組み合わせるときに使います。両方を1つの文字列で渡すと、リクエストごとの部分が変わるとシステムプロンプト全体が変わり、静的な指示もキャッシュに当たりません。配列の形は Python SDK にはありません SYSTEM_PROMPT_DYNAMIC_BOUNDARYは@anthropic-ai/claude-agent-sdkから取り込み、配列の要素として単独で置きます。SDK は、印の前の文字列を1つのテキストブロック、後ろの文字列を2つ目のブロックとして送り、それぞれに別のキャッシュ境界を付けます。境界の両側の文字列は空行を挟んで連結され、印そのものは取り除かれます。印が複数あると最初のものが分割点で、残りは取り除かれます。印がなければ、全部が1つのブロックに連結されます(1つの文字列と同じ)。キャッシュのトークン数は、結果メッセージのcache_creation_input_tokensとcache_read_input_tokensで見ます(SDK の本番運用)- Claude Code がプロンプトを分けるのは、Claude API を直接呼ぶときと Claude Platform on AWS で動くときだけです。ほかの構成(Amazon Bedrock・Google Cloud の Agent Platform・Microsoft Foundry・LLM ゲートウェイ)では、プロンプト全体を1つのブロックで送ります(
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1のときも同じ) - CLI の
--system-promptや--system-prompt-fileでは、プロンプトが1つの文字列なので、配列がありません。静的な部分とリクエストごとの部分の間に、__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__だけの行を入れます。Claude Code は、そのような最初の行でプロンプトを同じ2つのブロックに分け、その行を取り除きます(Claude Code v2.1.275 以降)。SDK では、印の行を要らない配列の形が望ましいです
既存のセッションのプロンプトを変える#
既定では、resume や continue でセッションに戻るときに別の append や自前のプロンプトを渡しても、次のターンで Claude には届きません。Claude Code は、セッションの最初のリクエストでシステムプロンプトを記録し、セッションが圧縮されるまでその記録を再利用します。新しいテキストは、その圧縮の後か、新しいセッションで効きます。
- 実行中のセッションで指示を変える:システムプロンプトに入れた指示を、セッションの動いている間に変える必要があるとき(ユーザーがエージェントを読み取り専用のモードへ切り替えた、アプリで設定を編集した、など)は、
systemPromptを変えずに、新しい指示を会話に送ります。次のユーザーメッセージに含めるか、UserPromptSubmitかPostToolUseのフックのコールバックからadditionalContextを返します(「ワークスペースは読み取り専用になった」のような事実の文で書く)。SDK はフックが発火した位置で会話に差し込むので、記録されたプロンプトは変わりません - 文言を詰める間は記録を切る:文言を詰めていて、再開するセッションにも編集を届けたいときは、システムプロンプトのオブジェクトの形に
snapshotをfalseにして設定します。Claude Code は、リクエストごとにプロンプトを組み直します。プリセットと自前の形のsystemPrompt(Python はsystem_prompt)に使え、@anthropic-ai/claude-agent-sdkv0.3.257 以降、claude-agent-sdkv0.2.153 以降が必要です - 本番では記録を有効のままにします。切ると、再開したセッションで別の
appendや自前のプロンプトが次のターンに届きますが、そのリクエストはセッションのプロンプトキャッシュを再利用できません。API が preserved thinking を強制するところでは、Claude が前のターンの思考も失います - クラウドセッション以外で、
extraArgsで--bareを渡すかCLAUDE_CODE_SIMPLE=1を設定して Claude Code を bare モードで始めると、snapshot: trueを設定しない限り、記録は切れたままです appendや自前のプロンプトを既定で記録するのは、Claude Code v2.1.265 以降(TypeScript Agent SDK は v0.3.265 から、Python Agent SDK は v0.2.153 から同梱)が必要です。Claude Code v2.1.268 より前は、フィーチャーフラグを取得しないセッション(Amazon Bedrock・Google Cloud の Agent Platform・Microsoft Foundry を含む)は、リクエストごとにプロンプトを組み直し、snapshotが効きませんでした
システムプロンプトの外で足される文脈#
システムリマインダーは、セッション中に Claude Code が会話へ足すメッセージで、CLAUDE.md の内容やファイルがディスク上で変わったという注記のような文脈を Claude に渡します。会話の中で送るので、claude_code プリセットでも自前の文字列でも Claude に届きます。動きを変えやすいものは次のとおりです。
- プロジェクトの指示:
settingSourcesが読み込むCLAUDE.mdのファイル - 出力スタイルの指示:メインの会話での、有効な出力スタイルの指示
- コミットとプルリクエストの帰属:
attributionの設定のCo-Authored-Byと、プルリクエストのフッター - フックの出力:フックが
additionalContextとして返すテキスト - 使えるスキル:Claude が呼べるスキルの名前と説明
- 使えるサブエージェント:Claude が起こせるサブエージェントの名前と説明
- タスクリストの促し:タスク管理のツールがあるセッションで、Claude が何ターンかタスクリストに触れていないときの、更新を促す文
- ファイルの変更の注記:Claude が前に読んだファイルがディスク上で変わったという注記
Claude Code は CLAUDE.md の前に、その指示が既定の動きに優先するという一文を付けます。自前の文字列を systemPrompt に渡すなら、システムリマインダーとは何かを説く文を足します。claude_code プリセットにはあり、自前の文字列はプリセット全体を置き換えるからです。ないと、CLAUDE.md の内容やフックの出力が、ユーザーでなくアプリから来たと、プロンプトのどこにも書かれません。
エージェントが自前で持つ文脈を切る。 組み込みの文脈は、エージェントが同じ指針を自前で持つときに切ります。たとえば、プロンプトが「PROJ-142: fix login redirect の形で、トレーラーなしでコミットメッセージを書く」と言っても、Claude Code は各コミットメッセージを Co-Authored-By のトレーラーで終えるよう伝え続けるので、Claude は同じコミットに矛盾した2つの指示を受けます。設定のキーは settings オプションで、環境変数は env オプションで渡します(TypeScript の env は継承した環境を置き換えるので、process.env を展開します)。
| 組み込みの文脈 | 切る方法 |
|---|---|
| 組み込みのコミットとプルリクエストの指示と、git status のスナップショット | includeGitInstructions を false にするか、CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS=1 |
Co-Authored-By のトレーラーとプルリクエストのフッター |
attribution.commit と attribution.pr を自分のテキストにするか、空の文字列にして消す |
user か project の設定ソース(その CLAUDE.md を含む) |
settingSources から 'user' か 'project' を外す |
すべての CLAUDE.md のファイル |
CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 |
| タスクリストの促し・ファイルの変更の注記・スキルの一覧 | CLAUDE_CODE_DISABLE_ATTACHMENTS=1 |
- 組み込みのコミットとプルリクエストの指示は、リマインダーではなく、
Bashツールの説明の一部なので、自前のsystemPromptを渡しても Claude に届きます CLAUDE_CODE_DISABLE_ATTACHMENTSを設定すると、Claude Code は@のファイルの言及も、ファイルの内容に展開せず、プレーンテキストで送ります。使えるサブエージェントの一覧とバックグラウンドのタスクの通知は届きます
options: {
systemPrompt: { type: "preset", preset: "claude_code", append: "コミットメッセージは `PROJ-142: fix login redirect` の形で書く。" },
settings: {
attribution: { commit: "", pr: "" },
includeGitInstructions: false,
},
}
Claude が受け取ったものを見る。 SDK のメッセージストリームにはシステムリマインダーが含まれないので、コードが受け取るメッセージを読んでも、Claude が見たものは分かりません。Claude Code が送るリクエストを記録します。OTEL_LOG_RAW_API_BODIES を file:<dir> に設定すると、リクエストの本文をそのディレクトリへ書きます。または、ANTHROPIC_BASE_URL を、リクエストの本文を記録するプロキシへ向けます。記録したリクエストの messages 配列を見ると、リマインダーは、<system-reminder> タグで包まれたユーザーメッセージの中か、モデルによっては system ロールの別のメッセージとして現れます。
組み合わせる#
永続する出力スタイルや CLAUDE.md が長期の動きを決め、append が、保存した設定に触れずにセッション固有の指示を重ねます。たとえば、Code Reviewer の出力スタイルが有効なとき、append のブロックでセッション固有の重点(OAuth とトークンの保存など)を人格の上に重ね、保存した出力スタイルを変えずに、1回のレビューで優先できます。
公式ドキュメント(英語)
- Give Claude custom tools
- Connect to external tools with MCP
- Scale to many tools with tool search
- Configure permissions
- Intercept and control agent behavior with hooks
- Subagents in the SDK
- Extend agents with skills
- Plugins in the SDK
- Modifying system prompts
2026年10月5日時点の内容をもとに、日本語でまとめています。