12 ファイル変更 +51 -38
この更新の概要
SDKにおけるスキルの有効化方法が変更され、skillsオプション指定時にallowedToolsリストへSkillを明示的に含める必要があることが明記されました。フック関数の戻り値が刷新され、従来のdecision/reason形式からhookSpecificOutputオブジェクトを使用する形式へと移行し、既存の形式は非推奨となっています。プラグインの構成要件が緩和され、plugin.jsonマニフェストファイルがなくてもディレクトリ構造からコンポーネントを自動検出できるようになりました。スラッシュコマンドの引数参照が$1からではなく$0から始まる形式に修正され、MCP関連ツールの名称も変更されています。
スキルの有効化時にallowedToolsへSkillを含める必要がある旨の追記と、フックの戻り値におけるhookSpecificOutput形式への変更が反映されています。
@@ -115,7 +115,7 @@ For how to structure and organize CLAUDE.md content, see [Manage Claude's memory
Skills are markdown files that give your agent specialized knowledge and invocable workflows. Unlike `CLAUDE.md` (which loads every session), skills load on demand. The agent receives skill descriptions at startup and loads the full content when relevant.
Skills are discovered from the filesystem through `settingSources`. When the `skills` option on `query()` is omitted, discovered user and project skills are enabled and the Skill tool is available, matching CLI behavior. To control which skills are enabled, pass `skills` as `"all"`, a list of skill names, or `[]` to disable all. The SDK enables the Skill tool automatically when `skills` is set, so you do not need to add it to `allowedTools`.
Skills are discovered from the filesystem through `settingSources`. When the `skills` option on `query()` is omitted, discovered user and project skills are enabled and the Skill tool is available, matching CLI behavior. To control which skills are enabled, pass `skills` as `"all"`, a list of skill names, or `[]` to disable all. When `skills` is set, the SDK adds the Skill tool to `allowedTools` automatically. If you also pass an explicit `tools` list, include `"Skill"` in that list so Claude can invoke skills.
```python Python theme={null}
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
@@ -166,7 +166,7 @@ The SDK supports two ways to define hooks, and they run side by side:
Both types execute during the same hook lifecycle. If you already have hooks in your project's `.claude/settings.json` and you set `settingSources: ["project"]`, those hooks run automatically in the SDK with no extra configuration.
Hook callbacks receive the tool input and return a decision dict. Returning `{}` (an empty dict) means allow the tool to proceed. Returning `{"decision": "block", "reason": "..."}` prevents execution and the reason is sent to Claude as the tool result. See the [hooks guide](/en/agent-sdk/hooks) for the full callback signature and return types.
Hook callbacks receive the tool input and return a decision dict. Returning `{}` means allow the tool to proceed. To block execution, return a `hookSpecificOutput` object with `permissionDecision: "deny"` and a `permissionDecisionReason`. The reason is sent to Claude as the tool result. The top-level `decision` and `reason` fields are deprecated for `PreToolUse`. See the [hooks guide](/en/agent-sdk/hooks) for the full callback signature and return types.
```python Python theme={null}
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, ResultMessage
@@ -178,7 +178,13 @@ from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, ResultMessa
async def audit_bash(input_data, tool_use_id, context):
command = input_data.get("tool_input", {}).get("command", "")
if "rm -rf" in command:
return {"decision": "block", "reason": "Destructive command blocked"}
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked",
}
}
return {} # Empty dict: allow the tool to proceed
# Filesystem hooks from .claude/settings.json run automatically
@@ -208,7 +214,13 @@ const auditBash = async (input: HookInput): Promise<HookJSONOutput> => {
if (input.hook_event_name !== "PreToolUse") return {};
const toolInput = input.tool_input as { command?: string };
if (toolInput.command?.includes("rm -rf")) {
return { decision: "block", reason: "Destructive command blocked" };
return {
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Destructive command blocked",
},
};
}
return {}; // Empty object: allow the tool to proceed
};
@@ -235,7 +247,7 @@ for await (const message of query({
| Hook type | Best for |
| :- | :- |
| **Filesystem** (`settings.json`) | Sharing hooks between CLI and SDK sessions. Supports `"command"` (shell scripts), `"http"` (POST to an endpoint), `"mcp_tool"` (call a connected MCP server's tool), `"prompt"` (LLM evaluates a prompt), and `"agent"` (spawns a verifier agent). These fire in the main agent and any subagents it spawns. |
| **Programmatic** (callbacks in `query()`) | Application-specific logic; returning structured decisions; in-process integration. Scoped to the main session only. |
| **Programmatic** (callbacks in `query()`) | Application-specific logic, structured decisions, and in-process integration. These also fire inside subagents. The callback receives `agent_id` and `agent_type` to distinguish. |
The TypeScript SDK supports additional hook events beyond Python, including `SessionStart`, `SessionEnd`, `TeammateIdle`, and `TaskCompleted`. See the [hooks guide](/en/agent-sdk/hooks) for the full event compatibility table.
@@ -217,7 +217,7 @@ Every hook callback receives three arguments:
Your callback returns an object with two categories of fields:
- **Top-level fields** work the same on every event: `systemMessage` shows a message to the user, and `continue` (`continue_` in Python) determines whether the agent keeps running after this hook.
- **`hookSpecificOutput`** controls the current operation. The fields inside depend on the hook event type. For `PreToolUse` hooks, this is where you set `permissionDecision` (`"allow"`, `"deny"`, `"ask"`, or `"defer"`), `permissionDecisionReason`, and `updatedInput`. Returning `"defer"` ends the query so you can [resume it later](/en/hooks#defer-a-tool-call-for-later). For `PostToolUse` hooks, you can set `additionalContext` to append information to the tool result, or `updatedToolOutput` to replace the tool's output entirely before Claude sees it.
- **`hookSpecificOutput`** controls the current operation. The fields inside depend on the hook event type. For `PreToolUse` hooks, this is where you set `permissionDecision` (`"allow"`, `"deny"`, `"ask"`, or `"defer"`), `permissionDecisionReason`, and `updatedInput`. Returning `"defer"` ends the query so you can [resume it later](/en/hooks#defer-a-tool-call-for-later). For `PostToolUse` hooks, you can set `additionalContext` to append information to the tool result. To replace the tool's output before Claude sees it, set `updatedToolOutput`, which works for any tool in both SDKs. The older `updatedMCPToolOutput` field replaces MCP tool output only and is deprecated.
Return `{}` to allow the operation without changes. SDK callback hooks use the same JSON output format as [Claude Code shell command hooks](/en/hooks#json-output), which documents every field and event-specific option. For the SDK type definitions, see the [TypeScript](/en/agent-sdk/typescript#synchookjsonoutput) and [Python](/en/agent-sdk/python#synchookjsonoutput) SDK references.
@@ -581,7 +581,14 @@ for await (const message of query({
### Forward notifications to Slack
Use `Notification` hooks to receive system notifications from the agent and forward them to external services. Notifications fire for specific event types: `permission_prompt` (Claude needs permission), `idle_prompt` (Claude is waiting for input), `auth_success` (authentication completed), `elicitation_dialog` (Claude is prompting the user), `elicitation_response` (the user answered an elicitation), and `elicitation_complete` (an elicitation closed). Each notification includes a `message` field with a human-readable description and optionally a `title`.
Use `Notification` hooks to receive system notifications from the agent and forward them to external services. Notifications fire for event types such as:
- `permission_prompt` when Claude needs permission
- `idle_prompt` when Claude is waiting for input
- `auth_success` when authentication completes
- `elicitation_dialog`, `elicitation_complete`, and `elicitation_response` for user-prompt elicitation flows
Each notification includes a `message` field with a human-readable description and optionally a `title`.
This example forwards every notification to a Slack channel. It requires a [Slack incoming webhook URL](https://api.slack.com/messaging/webhooks), which you create by adding an app to your Slack workspace and enabling incoming webhooks:
@@ -723,7 +730,7 @@ const myHook: HookCallback = async (input, toolUseID, { signal }) => {
};
```
- You must also return `permissionDecision: 'allow'` or `'ask'` for the input modification to take effect
- Return `permissionDecision: 'allow'` to auto-approve the modified input, or `'ask'` to show it to the user for approval
- Include `hookEventName` in `hookSpecificOutput` to identify which hook type the output is for
@@ -69,7 +69,7 @@ Plugin paths can be:
- **Relative paths**: Resolved relative to your current working directory (for example, `"./plugins/my-plugin"`)
- **Absolute paths**: Full file system paths (for example, `"/home/user/plugins/my-plugin"`)
The path should point to the plugin's root directory (the directory containing `.claude-plugin/plugin.json`).
The path should point to the plugin's root directory: the parent of `skills/`, `agents/`, `hooks/`, `commands/` (legacy), or `.claude-plugin/`, not a subdirectory.
## Verifying plugin installation
@@ -250,12 +250,12 @@ if __name__ == "__main__":
## Plugin structure reference
A plugin directory must contain a `.claude-plugin/plugin.json` manifest file. It can optionally include:
A plugin directory typically contains a `.claude-plugin/plugin.json` manifest file. The manifest is optional. When omitted, Claude Code auto-discovers components from the directory layout. The directory can include:
```text
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Required: plugin manifest
│ └── plugin.json # Plugin manifest (optional, components auto-discovered without it)
├── skills/ # Agent Skills (invoked autonomously or via /skill-name)
│ └── my-skill/
│ └── SKILL.md
@@ -308,9 +308,9 @@ plugins: [
If your plugin doesn't appear in the init message:
1. **Check the path**: Ensure the path points to the plugin root directory (containing `.claude-plugin/`)
2. **Validate plugin.json**: Ensure your manifest file has valid JSON syntax
3. **Check file permissions**: Ensure the plugin directory is readable
1. **Check the path**: ensure the path points to the plugin root directory, the parent of `skills/`, `agents/`, `hooks/`, `commands/` (legacy), or `.claude-plugin/`
2. **Validate plugin.json**: if your plugin includes a manifest, ensure it has valid JSON syntax
3. **Check file permissions**: ensure the plugin directory is readable
### Skills not appearing
@@ -811,7 +811,7 @@ class ClaudeAgentOptions:
| `plugins` | `list[SdkPluginConfig]` | `[]` | Load custom plugins from local paths. See [Plugins](/en/agent-sdk/plugins) for details |
| `sandbox` | [`SandboxSettings`](#sandboxsettings) ` \| None` | `None` | Configure sandbox behavior programmatically. See [Sandbox settings](#sandboxsettings) for details |
| `setting_sources` | `list[SettingSource] \| None` | `None` (CLI defaults: all sources) | Control which filesystem settings to load. Pass `[]` to disable user, project, and local settings. Managed policy settings load regardless. See [Use Claude Code features](/en/agent-sdk/claude-code-features#what-settingsources-does-not-control) |
| `skills` | `list[str] \| Literal["all"] \| None` | `None` | Skills available to the session. Pass `"all"` to enable every discovered skill, or a list of skill names. When set, the SDK enables the Skill tool automatically without listing it in `allowed_tools`. See [Skills](/en/agent-sdk/skills) |
| `skills` | `list[str] \| Literal["all"] \| None` | `None` | Skills available to the session. Pass `"all"` to enable every discovered skill, or a list of skill names. When set, the SDK adds the Skill tool to `allowed_tools` automatically. If you also pass `tools`, include `"Skill"` in that list. See [Skills](/en/agent-sdk/skills) |
| `max_thinking_tokens` | `int \| None` | `None` | *Deprecated* - Maximum tokens for thinking blocks. Use `thinking` instead |
| `thinking` | [`ThinkingConfig`](#thinkingconfig) ` \| None` | `None` | Controls extended thinking behavior. Takes precedence over `max_thinking_tokens` |
| `effort` | [`EffortLevel`](#effortlevel) ` \| None` | `None` | Effort level for thinking depth |
@@ -2816,7 +2816,7 @@ As of Claude Code v2.1.142, `TodoWrite` is disabled by default. Use `TaskCreate`
### ListMcpResources
**Tool name:** `ListMcpResources`
**Tool name:** `ListMcpResourcesTool`
**Input:**
@@ -2845,7 +2845,7 @@ As of Claude Code v2.1.142, `TodoWrite` is disabled by default. Use `TaskCreate`
### ReadMcpResource
**Tool name:** `ReadMcpResource`
**Tool name:** `ReadMcpResourceTool`
**Input:**
@@ -45,7 +45,7 @@ Both SDKs offer an interface that tracks session state for you across calls, so
### Python: `ClaudeSDKClient`
[`ClaudeSDKClient`](/en/agent-sdk/python#claudesdkclient) handles session IDs internally. Each call to `client.query()` automatically continues the same session. Call [`client.receive_response()`](/en/agent-sdk/python#claudesdkclient) to iterate over the messages for the current query. The client is typically used as an async context manager.
[`ClaudeSDKClient`](/en/agent-sdk/python#claudesdkclient) handles session IDs internally. Each call to `client.query()` automatically continues the same session. Call [`client.receive_response()`](/en/agent-sdk/python#claudesdkclient) to iterate over the messages for the current query. Use the client as an async context manager so connection setup and teardown are handled for you, or call `connect()` and `disconnect()` manually.
This example runs two queries against the same `client`. The first asks the agent to analyze a module; the second asks it to refactor that module. Because both calls go through the same client instance, the second query has full context from the first without any explicit `resume` or session ID:
@@ -301,6 +301,6 @@ Both SDKs also expose functions for looking up and mutating individual sessions:
## Related resources
- [How the agent loop works](/en/agent-sdk/agent-loop): Understand turns, messages, and context accumulation within a session
- [File checkpointing](/en/agent-sdk/file-checkpointing): Track and revert file changes across sessions
- [File checkpointing](/en/agent-sdk/file-checkpointing): Snapshot and revert file changes the agent made within a session
- [Python `ClaudeAgentOptions`](/en/agent-sdk/python#claudeagentoptions): Full session option reference for Python
- [TypeScript `Options`](/en/agent-sdk/typescript#options): Full session option reference for TypeScript
@@ -29,7 +29,7 @@ Skills are discovered through the filesystem setting sources. With default `quer
## Using Skills with the SDK
Set the `skills` option on `query()` to control which Skills are available to the session. When omitted, discovered Skills are enabled and the Skill tool is available, matching CLI behavior. Pass `"all"` to enable every discovered Skill, a list of Skill names to enable only those, or `[]` to disable all. When you set `skills`, the SDK enables the Skill tool automatically, so you do not need to list it in `allowedTools`.
Set the `skills` option on `query()` to control which Skills are available to the session. When omitted, discovered Skills are enabled and the Skill tool is available, matching CLI behavior. Pass `"all"` to enable every discovered Skill, a list of Skill names to enable only those, or `[]` to disable all. When you set `skills`, the SDK adds the Skill tool to `allowedTools` automatically. If you also pass an explicit `tools` list, include `"Skill"` in that list so Claude can invoke skills.
Once configured, Claude automatically discovers Skills from the filesystem and invokes them when relevant to the user's request.
@@ -232,7 +232,7 @@ argument-hint: [issue-number] [priority]
description: Fix a GitHub issue
---
Fix issue #$1 with priority $2.
Fix issue #$0 with priority $1.
Check the issue description and implement the necessary changes.
```
@@ -246,7 +246,7 @@ for await (const message of query({
prompt: "/fix-issue 123 high",
options: { maxTurns: 5 }
})) {
// Command will process with $1="123" and $2="high"
// Command will process with $0="123" and $1="high"
if (message.type === "result" && message.subtype === "success") {
console.log("Issue fixed:", message.result);
}
@@ -260,7 +260,7 @@ from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
# Pass arguments to custom command
async for message in query(prompt="/fix-issue 123 high", options=ClaudeAgentOptions(max_turns=5)):
# Command will process with $1="123" and $2="high"
# Command will process with $0="123" and $1="high"
if isinstance(message, ResultMessage):
print("Issue fixed:", message.result)
@@ -363,9 +363,6 @@ for await (const message of query({
## Known limitations
Some SDK features are incompatible with streaming:
- **Extended thinking**: when you explicitly set `max_thinking_tokens` (Python) or `maxThinkingTokens` (TypeScript), `StreamEvent` messages are not emitted. You'll only receive complete messages after each turn. Note that thinking is disabled by default in the SDK, so streaming works unless you enable it.
- **Structured output**: the JSON result appears only in the final `ResultMessage.structured_output`, not as streaming deltas. See [structured outputs](/en/agent-sdk/structured-outputs) for details.
## Next steps
@@ -68,8 +68,6 @@ Send multiple messages that process sequentially, with ability to interrupt
Full access to all tools and custom MCP servers during the session
Use lifecycle hooks to customize behavior at various points
See responses as they're generated, not just final results
Maintain conversation context across multiple turns naturally
@@ -204,7 +202,7 @@ Single message input is simpler but more limited.
Use single message input when:
- You need a one-shot response
- You do not need image attachments, hooks, etc.
- You do not need image attachments or mid-session control methods
- You need to operate in a stateless environment, such as a lambda function
### Limitations
@@ -214,7 +212,6 @@ Single message input mode does **not** support:
- Direct image attachments in messages
- Dynamic message queueing
- Real-time interruption
- Hook integration
- Natural multi-turn conversations
### Implementation Example
@@ -443,7 +443,7 @@ Configuration object for the `query()` function.
| `sessionStoreFlush` | `'batched' \| 'eager'` | `'batched'` | *Alpha.* Flush mode for `sessionStore`. Ignored when `sessionStore` is not set |
| `settings` | `string \| Settings` | `undefined` | Inline [settings](/en/settings) object or path to a settings file. Populates the flag-settings layer in the [precedence order](/en/settings#settings-precedence). Change at runtime with [`applyFlagSettings()`](#applyflagsettings) |
| `settingSources` | [`SettingSource`](#settingsource)`[]` | CLI defaults (all sources) | Control which filesystem settings to load. Pass `[]` to disable user, project, and local settings. Managed policy settings load regardless. See [Use Claude Code features](/en/agent-sdk/claude-code-features#what-settingsources-does-not-control) |
| `skills` | `string[] \| 'all'` | `undefined` | Skills available to the session. Pass `'all'` to enable every discovered skill, or a list of skill names. When set, the SDK enables the Skill tool automatically without listing it in `allowedTools`. See [Skills](/en/agent-sdk/skills) |
| `skills` | `string[] \| 'all'` | `undefined` | Skills available to the session. Pass `'all'` to enable every discovered skill, or a list of skill names. When set, the SDK adds the Skill tool to `allowedTools` automatically. If you also pass `tools`, include `'Skill'` in that list. See [Skills](/en/agent-sdk/skills) |
| `spawnClaudeCodeProcess` | `(options: SpawnOptions) => SpawnedProcess` | `undefined` | Custom function to spawn the Claude Code process. Use to run Claude Code in VMs, containers, or remote environments |
| `stderr` | `(data: string) => void` | `undefined` | Callback for stderr output |
| `strictMcpConfig` | `boolean` | `false` | Use only the servers passed in `mcpServers` and ignore project `.mcp.json`, user settings, plugin-provided MCP servers, and [claude.ai connectors](/en/mcp#use-mcp-servers-from-claude-ai) |
@@ -2042,7 +2042,7 @@ Exits planning mode. Optionally specifies prompt-based permissions needed to imp
### ListMcpResources
**Tool name:** `ListMcpResources`
**Tool name:** `ListMcpResourcesTool`
```typescript
type ListMcpResourcesInput = {
@@ -2054,7 +2054,7 @@ Lists available MCP resources from connected servers.
### ReadMcpResource
**Tool name:** `ReadMcpResource`
**Tool name:** `ReadMcpResourceTool`
```typescript
type ReadMcpResourceInput = {
@@ -2583,7 +2583,7 @@ Returns the plan state after exiting plan mode.
### ListMcpResources
**Tool name:** `ListMcpResources`
**Tool name:** `ListMcpResourcesTool`
```typescript
type ListMcpResourcesOutput = Array<{
@@ -2599,7 +2599,7 @@ Returns an array of available MCP resources.
### ReadMcpResource
**Tool name:** `ReadMcpResource`
**Tool name:** `ReadMcpResourceTool`
```typescript
type ReadMcpResourceOutput = {
@@ -209,7 +209,7 @@ Repeated blocks usually mean the classifier is missing context about your infras
Each action goes through a fixed decision order. The first matching step wins:
1. Actions matching your [allow or deny rules](/en/permissions#manage-permissions) resolve immediately
1. Actions matching your [allow or deny rules](/en/permissions#manage-permissions) resolve immediately, except writes to [protected paths](#protected-paths), which route to the classifier even when an allow rule matches
2. Read-only actions and file edits in your working directory are auto-approved, except writes to [protected paths](#protected-paths)
3. Everything else goes to the classifier
4. If the classifier blocks, Claude receives the reason and tries an alternative
@@ -18,7 +18,7 @@ Claude Code supports two ways to add custom skills, agents, and hooks:
| Approach | Skill names | Best for |
| :- | :- | :- |
| **Standalone** (`.claude/` directory) | `/hello` | Personal workflows, project-specific customizations, quick experiments |
| **Plugins** (directories with `.claude-plugin/plugin.json`) | `/plugin-name:hello` | Sharing with teammates, distributing to community, versioned releases, reusable across projects |
| **Plugins** (self-contained directories with skills, agents, hooks, or a `.claude-plugin/plugin.json` manifest) | `/plugin-name:hello` | Sharing with teammates, distributing to community, versioned releases, reusable across projects |
**Use standalone configuration when**:
@@ -49,7 +49,7 @@ If you don't see the `/plugin` command, update Claude Code to the latest version
### Create your first plugin
Every plugin lives in its own directory containing a manifest and your skills, agents, or hooks. Create one now:
Every plugin lives in its own directory containing your skills, agents, or hooks, optionally alongside a `.claude-plugin/plugin.json` manifest. Create one now:
```bash theme={null}
mkdir my-first-plugin