One read of Claude Code CLI
18 pages moved out of 186 read.
agent-sdk/typescript Changed · +2 / -2 lines
This page is larger than the 256 KiB this site keeps, so one side of the diff below stops where the stored text does.
On other models, Claude Code provides the Task tools by default and `TodoWrite` only when you set `CLAUDE_CODE_ENABLE_TASKS=0`. - See [Model availability](/docs/en/agent-sdk/todo-tracking#model-availability) to opt in and [Migrate to Task tools](/docs/en/agent-sdk/todo-tracking#migrate-to-task-tools) to update your monitoring code. + See [Model availability](/docs/en/agent-sdk/todo-tracking#model-availability) to opt in. </Note> ### TaskCreate
On other models, Claude Code provides the Task tools by default and `TodoWrite` only when you set `CLAUDE_CODE_ENABLE_TASKS=0`. - See [Model availability](/docs/en/agent-sdk/todo-tracking#model-availability) to opt in and [Migrate to Task tools](/docs/en/agent-sdk/todo-tracking#migrate-to-task-tools) to update your monitoring code. + See [Model availability](/docs/en/agent-sdk/todo-tracking#model-availability) to opt in. </Note> ### TaskCreate
### `ModelUsage` -Per-model usage statistics returned in result messages. The `costUSD` value is a client-side estimate. See [Track cost and usage](/docs/en/agent-sdk/cost-tracking) for billing ca +Per-model usage statistics returned in result messages. The `costUSD` value is a client-side estimate. See [Track cost and usage](/docs/en/agent-sdk/cost-tracking) for billing caveats. + +```typescript theme={null} +type ModelUsage = { + inputTokens: number; + outputTokens: number; + cacheReadInputTokens: number; + cacheCreationInputTokens: number; + webSearchRequests: number; + costUSD: number; + contextWin
agent-sdk/file-checkpointing Changed · +0 / -6 lines
File rewinding restores files on disk to a previous state. It does not rewind the conversation itself. The conversation history and context remain intact after calling `rewindFiles()` (TypeScript) or `rewind_files()` (Python). </Note> -The checkpoint system tracks: - -* Files created during the session -* Files modified during the session -* The original content of modified files - When you rewind to a checkpoint, Claude Code deletes the files it created and restores the files it modified to their content at that point. Claude Code skips a tracked path that is a symlink, hard link, or other non-regular file. It also skips a tracked file whose parent directory no longer resolves to its checkpoint-time location, or whose backup it can't read safely. [`RewindFilesResult`](/docs/en/agent-sdk/typescript#rewindfilesresult) counts every skipped path in its `skippedLinks` field. Skipping requires Claude Code v2.1.216 or later; before v2.1.216, a rewind wrote and deleted through links at tracked paths. ## Implement checkpointing
agent-sdk/hooks Changed · +7 / -13 lines
SDK matchers follow the same rules as [matchers in settings files](/docs/en/hooks#matcher-patterns). That section documents the exact-string and regular-expression evaluation paths, their version requirements, and the matcher values for each event type. -| Option | Type | Default | Description | -| --------- | ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `matcher` | `string` | `undefined` | Pattern matched against the event's filter field, following the [rules for matchers in settings files](/docs/en/hooks#matcher-patterns). For tool hooks, this is the tool name. Built-in tools include `Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`, `WebFetch`, `Agent`, and others (see [Tool Input Types](/docs/en/agent-sdk/typescript#tool-input-types) for the full list). MCP tools use the pattern `mcp__<server>__<action>`. | -| `hooks` | `HookCallback[]` | - | Required. Array of callback functions to execute when the pattern matches | -| `timeout` | `number` | `undefined` | Timeout in seconds. When omitted, Claude Code applies the [event's default timeout](#hook-timeout). Your SDK callbacks follow the `command` hook defaults | +| Option | Type | Default | Description | +| --------- | ---------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `matcher` | `string` | `undefined` | Pattern matched against the event's filter field, following the [rules for matchers in settings files](/docs/en/hooks#matcher-patterns). For tool hooks, this is the tool name. Built-in tools include `Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`, `WebFetch`, `Agent`, and others (see [Tool Input Types](/docs/en/agent-sdk/typescript#tool-input-types) for the full list). MCP tools use the pattern `mcp__<server>__<action>`, where `<server>` is the key you use in the `mcpServers` configuration. | +| `hooks` | `HookCallback[]` | - | Required. Array of callback functions to execute when the pattern matches | +| `timeout` | `number` | `undefined` | Timeout in seconds. When omitted, Claude Code applies the [event's default timeout](#hook-timeout). Your SDK callbacks follow the `command` hook defaults | -Use the `matcher` pattern to target specific tools whenever possible. A matcher with `'Bash'` only runs for Bash commands, while omitting the pattern runs your callbacks for every occurrence of the event. - -<Tip> - **Discovering tool names:** See [Tool Input Types](/docs/en/agent-sdk/typescript#tool-input-types) for the full list of built-in tool names, or add a hook without a matcher to log all tool calls your session makes. - - **MCP tool naming:** MCP tools always start with `mcp__` followed by the server name and action: `mcp__<server>__<action>`. For example, if you configure a server named `playwright`, its tools are named `mcp__playwright__browser_screenshot`, `mcp__playwright__browser_click`, and so on. The server name comes from the key you use in the `mcpServers` configuration. -</Tip> +Use the `matcher` pattern to target specific tools whenever possible. A matcher with `'Bash'` only runs for Bash commands, while omitting the pattern runs your callbacks for every occurrence of the event. Omit it on purpose to log every tool call your session makes. ### Callback functions
agent-sdk/subagents Changed · +9 / -24 lines
### Context isolation ### Parallelization ### Specialized instructions and knowledge ### Tool restrictions
## Benefits of using subagents -### Context isolation +Because subagents are separate agent instances, delegating work to them gives you four benefits: -Each subagent runs in its own fresh conversation. Intermediate tool calls and results stay inside the subagent; only its final message returns to the parent. See [What subagents inherit](#what-subagents-inherit) for exactly what's in the subagent's context. +* **Context isolation**: each subagent runs in its own conversation, which starts fresh unless the subagent is a [fork](/docs/en/sub-agents#fork-the-current-conversation). Either way, intermediate tool calls and results stay inside the subagent; only its final message returns to the parent. A `research-assistant` subagent can explore dozens of files without any of that content accumulating in the main conversation. The parent receives a concise summary, not every file the subagent read. See [What subagents inherit](#what-subagents-inherit) for exactly what's in the subagent's context. +* **Parallelization**: multiple subagents can run concurrently, so independent subtasks finish in the time of the slowest one rather than the sum of all of them. During a code review, you can run `style-checker`, `security-scanner`, and `test-coverage` subagents simultaneously instead of sequentially. +* **Specialized instructions and knowledge**: each subagent can have a tailored system prompt with specific expertise, best practices, and constraints. A `database-migration` subagent can have detailed knowledge about SQL best practices, rollback strategies, and data integrity checks that would be unnecessary noise in the main agent's instructions. +* **Tool restrictions**: subagents can be limited to specific tools, reducing the risk of unintended actions. A `doc-reviewer` subagent might only have access to Read and Grep tools, ensuring it can analyze but never accidentally modify your documentation files. -**Example:** a `research-assistant` subagent can explore dozens of files without any of that content accumulating in the main conversation. The parent receives a concise summary, not every file the subagent read. - -### Parallelization - -Multiple subagents can run concurrently, so independent subtasks finish in the time of the slowest one rather than the sum of all of them. - -**Example:** during a code review, you can run `style-checker`, `security-scanner`, and `test-coverage` subagents simultaneously instead of sequentially. - -### Specialized instructions and knowledge - -Each subagent can have tailored system prompts with specific expertise, best practices, and constraints. - -**Example:** a `database-migration` subagent can have detailed knowledge about SQL best practices, rollback strategies, and data integrity checks that would be unnecessary noise in the main agent's instructions. - -### Tool restrictions - -Subagents can be limited to specific tools, reducing the risk of unintended actions. - -**Example:** a `doc-reviewer` subagent might only have access to Read and Grep tools, ensuring it can analyze but never accidentally modify your documentation files. - ## Create subagents ### Programmatic definition (recommended)
## What subagents inherit -A subagent's context window starts fresh, with no parent conversation, but isn't empty. The only content you pass from parent to subagent is the Agent tool's prompt string, so include any file paths, error messages, or decisions the subagent needs directly in that prompt. +Unless the subagent is a [fork](/docs/en/sub-agents#fork-the-current-conversation), its context window starts fresh, with no parent conversation, but isn't empty. The only content you pass from parent to subagent is the Agent tool's prompt string, so include any file paths, error messages, or decisions the subagent needs directly in that prompt. A subagent that has the [`SendMessage`](/docs/en/tools-reference) tool starts with a list of the other named agents running in the session, so it knows which names it can send messages to. Claude Code adds the list to the subagent's first turn automatically. A [fork](/docs/en/sub-agents#fork-the-current-conversation) doesn't get the list because it inherits the parent conversation instead. The list requires Claude Code v2.1.206 or later. + +The table below lists what a non-fork subagent's context contains and what it leaves out. | The subagent receives | The subagent doesn't receive | | :------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------- |
agent-sdk/todo-tracking Changed · +272 / -247 lines
# Track todos ## Model availability ## Todo lifecycle ## When Claude creates todos ### Monitor todo changes ### Display progress in real time ## Related documentation # Todo Lists ### Model availability ### Todo Lifecycle ### When Todos Are Used ### Monitoring Todo Changes ### Real-time Progress Display ## Migrate to Task tools ## Related Documentation
The two sides of this change are too far apart to line up, so this is the differ's own diff of it.
-# Todo Lists - -> Track and display todos using the Claude Agent SDK for organized task management - -The Claude Agent SDK includes built-in todo functionality that helps organize complex workflows and keep users informed about task progression. +# Track todos + +> Track todos in Agent SDK sessions and render Claude's progress in your application from structured tool calls + +On the models listed under [Model availability](#model-availability), Claude tracks multi-step work without a written todo list, and Claude Code leaves the [task-tracking tools](/docs/en/tools-reference#task-tool-availability) out of sessions by default. You don't need anything on this page for Claude to work through multi-step tasks on those models. + +In a session that has the task-tracking tools, Claude keeps a written todo list, updating each item's status as it works. You see each change in the message stream as a structured tool call. Opt a session in only when your application reads those tool calls, whether to log task activity or to render its own progress display. + +## Model availability <Note> On TypeScript Agent SDK 0.3.233 and later, or Python Agent SDK 0.2.139 and later, the following tools aren't available on Opus 4.8, Sonnet 5, Fable 5, Mythos 5, or later versions of those families unless you opt in:
On other models, Claude Code provides the Task tools by default and `TodoWrite` only when you set `CLAUDE_CODE_ENABLE_TASKS=0`. </Note> -### Model availability - -On the [models that don't get the task-tracking tools](/docs/en/tools-reference#task-tool-availability), you see no `tool_use` blocks for them in the message stream unless you opt in. If you point `cli_path` in Python or `pathToClaudeCodeExecutable` in TypeScript at your own Claude Code install, you get whichever tools that install provides. To get the same tools as on other models, do one of the following: - -* Name one of the tools in the [`allowedTools`](/docs/en/agent-sdk/permissions#allow-and-deny-rules) option, `allowed_tools` in Python +On the listed models, unless you opt a session in, you see no `tool_use` blocks for the tools in the message stream. The Agent SDK applies these defaults through the Claude Code binary that it bundles. If you point `pathToClaudeCodeExecutable` (TypeScript) or `cli_path` (Python) at your own Claude Code install, you get whichever tools that install provides, under its own defaults. To see the exact set in a running session, [check which tools are available](/docs/en/tools-reference#check-which-tools-are-available). To opt a session in, do one of the following: + +* Name one of the tools in the [`allowedTools`](/docs/en/agent-sdk/permissions#allow-and-deny-rules) (TypeScript) or `allowed_tools` (Python) option * List the tools in the `tools` option, which restricts the session's built-in tools to the ones it names. Include the tools you want alongside the other built-in tools you use * Set `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` in the `env` option, as the examples on this page do. In TypeScript, `env` replaces the subprocess environment, so spread `...process.env` to keep inherited variables. In Python, `env` is merged on top of the inherited environment -### Todo Lifecycle +## Todo lifecycle Claude moves each todo through a predictable lifecycle:
3. **Completed**: Claude marks it completed when the task finishes successfully 4. **Removed**: Claude deletes a todo it no longer needs by setting `status: "deleted"` in a `TaskUpdate` call -### When Todos Are Used +## When Claude creates todos In a [session that has the task-tracking tools](#model-availability), Claude creates todos for most multi-step work, such as: -* **Complex multi-step tasks** requiring 3 or more distinct actions +* **Complex multi-step tasks** requiring three or more distinct actions * **User-provided task lists** when multiple items are mentioned -* **Non-trivial operations** that benefit from progress tracking +* **Longer operations** that benefit from progress tracking * **Explicit requests** when users ask for todo organization -It may skip todos for very short or single-step requests. +Claude may skip todos for very short or single-step requests. ## Examples -Before running these examples, install the Claude Agent SDK by following the [quickstart](/docs/en/agent-sdk/quickstart). - -Each example runs until the agent finishes and yields its final result message. If a session reaches its turn limit first, that result message has the `error_max_turns` subtype. Check `subtype` to detect that ending. - -These examples use single-shot `query()` calls. After yielding an `error_max_turns` result, `query()` raises an error that includes `Reached maximum number of turns`. Each example wraps its loop in a try block to exit cleanly when that happens. - -See [Handle the result](/docs/en/agent-sdk/agent-loop#handle-the-result) for the result subtypes. - -### Monitoring Todo Changes - -<CodeGroup> - ```typescript TypeScript theme={null} - import { query } from "@anthropic-ai/claude-agent-sdk"; - - try { - for await (const message of query({ - prompt: "Optimize my React app performance and track progress with todos", - // Re-enable TodoWrite, which this example monitors. Without it, the SDK uses - // Task tools instead and these tool_use blocks never appear. ENABLE_TODO_TOOLS - // keeps the tools on models where Claude Code otherwise doesn't provide them. - options: { maxTurns: 15, env: { ...process.env, CLAUDE_CODE_ENABLE_TASKS: "0", CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } } - })) { - // Todo updates are reflected in the message stream - if (message.type === "assistant") { - for (const block of message.message.content) { - if (block.type === "tool_use" && block.name === "TodoWrite") { - const todos = block.input.todos; - - console.log("Todo Status Update:"); - todos.forEach((todo, index) => { - const status = - todo.status === "completed" ? "โ " : todo.status === "in_progress" ? "๐ง" : "โ"; - console.log(`${index + 1}. ${status} ${todo.content}`); - }); - } - } - } - } - } catch (error) { - // A single-shot query() throws after yielding an error result, - // such as when the maxTurns limit is hit. - console.log(`Session ended with an error: ${error}`); - } - ``` - - ```python Python theme={null} - import asyncio - - from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock - - - async def main(): - try: - async for message in query( - prompt="Optimize my React app performance and track progress with todos", - # Re-enable TodoWrite, which this example monitors. Without it, the SDK uses - # Task tools instead and these tool_use blocks never appear. ENABLE_TODO_TOOLS - # keeps the tools on models where Claude Code otherwise doesn't provide them. - options=ClaudeAgentOptions(max_turns=15, env={"CLAUDE_CODE_ENABLE_TASKS": "0", "CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"}), - ): - # Todo updates are reflected in the message stream - if isinstance(message, AssistantMessage): - for block in message.content: - if isinstance(block, ToolUseBlock) and block.name == "TodoWrite": - todos = block.input["todos"] - - print("Todo Status Update:") - for i, todo in enumerate(todos): - status = ( - "โ " - if todo["status"] == "completed" - else "๐ง" - if todo["status"] == "in_progress" - else "โ" - ) - print(f"{i + 1}. {status} {todo['content']}") - except Exception as error: - # A single-shot query() raises after yielding an error result, - # such as when the max_turns limit is hit. - print(f"Session ended with an error: {error}") - - - asyncio.run(main()) - ``` -</CodeGroup> - -### Real-time Progress Display - -<CodeGroup> - ```typescript TypeScript theme={null} - import { query } from "@anthropic-ai/claude-agent-sdk"; - - class TodoTracker { - private todos: any[] = []; - - displayProgress() { - if (this.todos.length === 0) return; - - const completed = this.todos.filter((t) => t.status === "completed").length; - const inProgress = this.todos.filter((t) => t.status === "in_progress").length; - const total = this.todos.length; - - console.log(`\nProgress: ${completed}/${total} completed`); - console.log(`Currently working on: ${inProgress} task(s)\n`); - - this.todos.forEach((todo, index) => { - const icon = - todo.status === "completed" ? "โ " : todo.status === "in_progress" ? "๐ง" : "โ"; - const text = todo.status === "in_progress" ? todo.activeForm : todo.content; - console.log(`${index + 1}. ${icon} ${text}`); - }); - } - - async trackQuery(prompt: string) { - try { - for await (const message of query({ - prompt, - // On every model, re-enable TodoWrite, which this tracker watches for. - options: { maxTurns: 20, env: { ...process.env, CLAUDE_CODE_ENABLE_TASKS: "0", CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } } - })) { - if (message.type === "assistant") { - for (const block of message.message.content) { - if (block.type === "tool_use" && block.name === "TodoWrite") { - this.todos = block.input.todos; - this.displayProgress(); - } - } - } - } - } catch (error) { - // A single-shot query() throws after yielding an error result, - // such as when the maxTurns limit is hit. - console.log(`Session ended with an error: ${error}`); - } - } - } - - // Usage - const tracker = new TodoTracker(); - await tracker.trackQuery("Build a complete authentication system with todos"); - ``` - - ```python Python theme={null} - import asyncio - - from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock - from typing import List, Dict - - - class TodoTracker: - def __init__(self): - self.todos: List[Dict] = [] - - def display_progress(self): - if not self.todos: - return - - completed = len([t for t in self.todos if t["status"] == "completed"]) - in_progress = len([t for t in self.todos if t["status"] == "in_progress"]) - total = len(self.todos) - - print(f"\nProgress: {completed}/{total} completed") - print(f"Currently working on: {in_progress} task(s)\n") - - for i, todo in enumerate(self.todos): - icon = ( - "โ " - if todo["status"] == "completed" - else "๐ง" - if todo["status"] == "in_progress" - else "โ" - ) - text = ( - todo["activeForm"] - if todo["status"] == "in_progress" - else todo["content"] - ) - print(f"{i + 1}. {icon} {text}") - - async def track_query(self, prompt: str): - try: - async for message in query( - prompt=prompt, - # On every model, re-enable TodoWrite, which this tracker watches for. - options=ClaudeAgentOptions(max_turns=20, env={"CLAUDE_CODE_ENABLE_TASKS": "0", "CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"}), - ): - if isinstance(message, AssistantMessage): - for block in message.content: - if isinstance(block, ToolUseBlock) and block.name == "TodoWrite": - self.todos = block.input["todos"] - self.display_progress() - except Exception as error: - # A single-shot query() raises after yielding an error result, - # such as when the max_turns limit is hit. - print(f"Session ended with an error: {error}") - - - # Usage - async def main(): - tracker = TodoTracker() - await tracker.track_query("Build a complete authentication system with todos") - - - asyncio.run(main()) - ``` -</CodeGroup> - -## Migrate to Task tools - -The Task tools split the single `TodoWrite` call into `TaskCreate` for each new item and `TaskUpdate` for each status change, with `TaskList` and `TaskGet` available for the model to read back the current list. Your monitoring code still inspects `tool_use` blocks in the assistant stream, but maintains a map keyed by task ID instead of replacing the whole list on every call. - -| With `TodoWrite` | With Task tools | -| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| One tool call rewrites the full `todos` array | `TaskCreate` adds one item, `TaskUpdate` patches one item by `taskId` | -| Match `block.name === "TodoWrite"` | Match `block.name === "TaskCreate"` or `"TaskUpdate"` | -| Item shape: `{ content, status, activeForm }` | `TaskCreate` input: `{ subject, description, activeForm?, metadata? }`. `TaskUpdate` input: `{ taskId, status?, subject?, description?, activeForm?, addBlocks?, addBlockedBy?, owner?, metadata? }`. `status` is `"pending"`, `"in_progress"`, or `"completed"`; set `status: "deleted"` to delete | -| Render `block.input.todos` directly | Accumulate items across calls, or read a snapshot from a `TaskList` tool result | - -The assigned task ID is not in the `TaskCreate` input. It comes back in the matching `tool_result` as `{ task: { id, subject } }`, so capture it from the result block to key your map. - -The following example shows the minimal change to the [Monitoring Todo Changes](#monitoring-todo-changes) loop. It leaves `CLAUDE_CODE_ENABLE_TASKS` unset, because the Task tools are the default, and sets only `CLAUDE_CODE_ENABLE_TODO_TOOLS=1`, the [opt-in](#model-availability) for the models that otherwise don't get the tools. It reads only `tool_use` inputs and skips capturing IDs from `tool_result` blocks. To render a complete list, watch for a `TaskList` tool result in the stream or accumulate `TaskCreate` results and `TaskUpdate` inputs into a map. - -The streamed `tool_use` input is the raw shape the model emitted. Claude Code repairs some close-but-incorrect key names before execution, mapping `id` or `task_id` to `taskId` and `active_form` to `activeForm`, but that repair is not reflected in the stream. Read `TaskUpdate` input fields defensively, as the samples below do, rather than assuming the canonical name is always present. +Before running these examples, install the Claude Agent SDK by following the [quickstart](/docs/en/agent-sdk/quickstart). Every example on this page shares the same permission setup and exit behavior: + +* **Permission mode**: the example prompts ask Claude to do real work on a project, so each example sets `permissionMode: "acceptEdits"` (TypeScript) or `permission_mode="acceptEdits"` (Python) to auto-approve the file edits that work produces. See [Permission modes](/docs/en/agent-sdk/permissions#permission-modes) for the alternatives. +* **Turn limit**: each example runs until the agent finishes and yields its final result message. If a session reaches its turn limit first, that result message has the `error_max_turns` subtype. Check `subtype` to detect that ending. +* **Error handling**: these examples use single-shot `query()` calls. After yielding an `error_max_turns` result, `query()` raises an error that includes `Reached maximum number of turns`. Each example wraps its loop in a try block to exit cleanly when that happens. See [Handle the result](/docs/en/agent-sdk/agent-loop#handle-the-result) for the result subtypes. + +<Note> + The task system messages, [`SDKTaskNotificationMessage`](/docs/en/agent-sdk/typescript#sdktasknotificationmessage) (TypeScript) or [`TaskNotificationMessage`](/docs/en/agent-sdk/python#tasknotificationmessage) (Python) among them, report background tasks such as backgrounded commands and subagents. In the message stream, you see todo activity as `tool_use` blocks in the assistant messages. +</Note> + +### Monitor todo changes + +The following example watches the assistant stream for `TaskCreate` and `TaskUpdate` `tool_use` blocks and prints a `+` line with each new task's subject and an update line with each status change's task ID and new status. Use this shape when you want a log of task activity rather than a rendered display. The `+` lines don't include the assigned IDs, so this log can't match updates back to their creates. To keep that correlation, capture the IDs as [Display progress in real time](#display-progress-in-real-time) does. + +The streamed `tool_use` input is the raw shape the model emitted. Claude Code repairs some close-but-incorrect key names before execution, mapping `id` or `task_id` to `taskId` and `active_form` to `activeForm`, but that repair is not reflected in the stream. Read `TaskUpdate` input fields defensively, as both examples on this page do, rather than assuming the canonical name is always present. <CodeGroup> ```typescript TypeScript theme={null}
for await (const message of query({ prompt: "Optimize my React app performance and track progress with todos", // Keeps the Task tools on models where Claude Code otherwise doesn't provide them. - options: { maxTurns: 15, env: { ...process.env, CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } }, + options: { maxTurns: 15, permissionMode: "acceptEdits", env: { ...process.env, CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } }, })) { if (message.type !== "assistant") continue; for (const block of message.message.content) {
async for message in query( prompt="Optimize my React app performance and track progress with todos", # Keeps the Task tools on models where Claude Code otherwise doesn't provide them. - options=ClaudeAgentOptions(max_turns=15, env={"CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"}), + options=ClaudeAgentOptions(max_turns=15, permission_mode="acceptEdits", env={"CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"}), ): if not isinstance(message, AssistantMessage): continue
if not isinstance(block, ToolUseBlock): continue if block.name == "TaskCreate": - print(f"+ {block.input['subject']}") + print(f"+ {block.input.get('subject', '')}") elif block.name == "TaskUpdate" and block.input.get("status"): task_id = ( block.input.get("taskId")
``` </CodeGroup> -## Related Documentation - -* [TypeScript SDK Reference](/docs/en/agent-sdk/typescript) -* [Python SDK Reference](/docs/en/agent-sdk/python) -* [Streaming vs Single Mode](/docs/en/agent-sdk/streaming-vs-single-mode) -* [Custom Tools](/docs/en/agent-sdk/custom-tools) +### Display progress in real time + +The following example watches the assistant stream for `TaskCreate` and `TaskUpdate` `tool_use` blocks and keeps a map of tasks keyed by task ID in a `TaskTracker` class, rerendering a progress summary on every change. The summary counts completed and in-progress tasks and shows each active item's `activeForm` label in place of its `subject`. Use this shape when your application maintains a progress display instead of logging each event. + +The assigned task ID isn't in the `TaskCreate` input. Claude Code delivers each tool's structured output on the user message that carries its `tool_result` block, in the `tool_use_result` field. For `TaskCreate`, that object is documented for TypeScript as `TaskCreateOutput` under [Tool Output Types](/docs/en/agent-sdk/typescript#tool-output-types), and in Python the field is a plain dict of the same shape. The tracker pairs each `tool_result` block with its `tool_use` call by `tool_use_id` and reads `task.id` from the paired message's `tool_use_result`. Claude can read the list back with `TaskList` and one task's full details with `TaskGet`. + +<CodeGroup> + ```typescript TypeScript theme={null} + import { query } from "@anthropic-ai/claude-agent-sdk"; + + type Task = { subject: string; activeForm?: string; status: string }; + + class TaskTracker { + private tasks = new Map<string, Task>(); + private pendingCreates = new Map<string, { subject: string; activeForm?: string }>(); + + displayProgress() { + if (this.tasks.size === 0) { + console.log("\nProgress: no open tasks\n"); + return; + } + + const items = [...this.tasks.values()]; + const completed = items.filter((t) => t.status === "completed").length; + const inProgress = items.filter((t) => t.status === "in_progress").length; + + console.log(`\nProgress: ${completed}/${this.tasks.size} completed`); + console.log(`Currently working on: ${inProgress} task(s)\n`); + + for (const [id, task] of this.tasks) { + const icon = + task.status === "completed" ? "โ " : task.status === "in_progress" ? "๐ง" : "โ"; + const text = task.status === "in_progress" && task.activeForm ? task.activeForm : task.subject; + console.log(`${id}. ${icon} ${text}`); + } + } + + handleToolUse(block: { id: string; name: string; input: unknown }) { + if (block.name === "TaskCreate") { + const input = block.input as { subject: string; activeForm?: string; active_form?: string }; + this.pendingCreates.set(block.id, { + subject: input.subject, + activeForm: input.activeForm ?? input.active_form, + }); + } else if (block.name === "TaskUpdate") { + const input = block.input as { + taskId?: string; + id?: string; + task_id?: string; + status?: string; + activeForm?: string; + active_form?: string; + }; + const taskId = input.taskId ?? input.id ?? input.task_id; + if (!taskId) return; + if (input.status === "deleted") { + this.tasks.delete(taskId); + this.displayProgress(); + return; + } + const task = this.tasks.get(taskId); + if (!task) return; + if (input.status) task.status = input.status; + const active = input.activeForm ?? input.active_form; + if (active) task.activeForm = active; + this.displayProgress(); + } + } + + handleToolResult(block: { tool_use_id: string; is_error?: boolean }, result: unknown) { + const create = this.pendingCreates.get(block.tool_use_id); + if (!create) return; + this.pendingCreates.delete(block.tool_use_id); + if (block.is_error) return; + // The result's user message carries the tool's structured output as + // tool_use_result; for TaskCreate that's TaskCreateOutput, + // { task: { id, subject } }. + const out = result as { task?: { id: string } }; + if (!out?.task?.id) return; + this.tasks.set(out.task.id, { ...create, status: "pending" }); + this.displayProgress(); + } + + async trackQuery(prompt: string) { + try { + for await (const message of query({ + prompt, + options: { maxTurns: 20, permissionMode: "acceptEdits", env: { ...process.env, CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } }, + })) { + if (message.type === "assistant") { + for (const block of message.message.content) { + if (block.type === "tool_use") this.handleToolUse(block); + } + } + if (message.type === "user" && Array.isArray(message.message.content)) { + for (const block of message.message.content) { + if (block.type === "tool_result") this.handleToolResult(block, message.tool_use_result); + } + } + } + } catch (error) { + // A single-shot query() throws after yielding an error result, + // such as when the maxTurns limit is hit. + console.log(`Session ended with an error: ${error}`); + } + } + } + + // Usage + const tracker = new TaskTracker(); + await tracker.trackQuery("Build a complete authentication system with todos"); + ``` + + ```python Python theme={null} + import asyncio + + from claude_agent_sdk import ( + query, + ClaudeAgentOptions, + AssistantMessage, + UserMessage, + ToolUseBlock, + ToolResultBlock, + ) + + + class TaskTracker: + def __init__(self): + self.tasks: dict[str, dict] = {} + self.pending_creates: dict[str, dict] = {} + + def display_progress(self): + if not self.tasks: + print("\nProgress: no open tasks\n") + return + + completed = len([t for t in self.tasks.values() if t["status"] == "completed"]) + in_progress = len([t for t in self.tasks.values() if t["status"] == "in_progress"]) + + print(f"\nProgress: {completed}/{len(self.tasks)} completed") + print(f"Currently working on: {in_progress} task(s)\n") + + for task_id, task in self.tasks.items(): + icon = ( + "โ " + if task["status"] == "completed" + else "๐ง" + if task["status"] == "in_progress" + else "โ" + ) + text = ( + task["activeForm"] + if task["status"] == "in_progress" and task.get("activeForm") + else task["subject"] + ) + print(f"{task_id}. {icon} {text}") + + def handle_tool_use(self, block: ToolUseBlock): + if block.name == "TaskCreate": + self.pending_creates[block.id] = { + "subject": block.input.get("subject", ""), + "activeForm": block.input.get("activeForm") or block.input.get("active_form"), + } + elif block.name == "TaskUpdate": + task_id = ( + block.input.get("taskId") + or block.input.get("id") + or block.input.get("task_id") + ) + if not task_id: + return + if block.input.get("status") == "deleted": + self.tasks.pop(task_id, None) + self.display_progress() + return + task = self.tasks.get(task_id) + if not task: + return + if block.input.get("status"): + task["status"] = block.input["status"] + active = block.input.get("activeForm") or block.input.get("active_form") + if active: + task["activeForm"] = active + self.display_progress() + + def handle_tool_result(self, block: ToolResultBlock, tool_use_result): + create = self.pending_creates.pop(block.tool_use_id, None) + if create is None or block.is_error: + return + # The result's user message carries the tool's structured output as + # tool_use_result; for TaskCreate that's {"task": {"id": ..., "subject": ...}}. + task = (tool_use_result or {}).get("task") or {} + if not task.get("id"): + return + self.tasks[task["id"]] = {**create, "status": "pending"} + self.display_progress() + + async def track_query(self, prompt: str): + try: + async for message in query( + prompt=prompt, + options=ClaudeAgentOptions( + max_turns=20, + permission_mode="acceptEdits", + env={"CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"}, + ), + ): + if isinstance(message, AssistantMessage): + for block in message.content: + if isinstance(block, ToolUseBlock): + self.handle_tool_use(block) + if isinstance(message, UserMessage) and isinstance(message.content, list): + for block in message.content: + if isinstance(block, ToolResultBlock): + self.handle_tool_result(block, message.tool_use_result) + except Exception as error: + # A single-shot query() raises after yielding an error result, + # such as when the max_turns limit is hit. + print(f"Session ended with an error: {error}") + + + # Usage + async def main(): + tracker = TaskTracker() + await tracker.track_query("Build a complete authentication system with todos") + + + asyncio.run(main()) + ``` +</CodeGroup> + +## Related documentation + +* [Agent SDK reference - TypeScript](/docs/en/agent-sdk/typescript): the options, types, and tool schemas for the TypeScript SDK, including the Task tool input and output types +* [Agent SDK reference - Python](/docs/en/agent-sdk/python): the options, types, and tool documentation for the Python SDK +* [Streaming Input](/docs/en/agent-sdk/streaming-vs-single-mode): the two input modes, and when to use streaming input instead of the single-shot calls these examples use +* [Give Claude custom tools](/docs/en/agent-sdk/custom-tools): define your own tools with the SDK's in-process MCP server
fullscreen Changed · +24 / -2 lines
#### How Claude Code counts failed starts
In that case Claude Code prints [`Cannot switch renderers in this session`](/docs/en/errors#cannot-switch-renderers-in-this-session) with the reasons. It doesn't switch or save anything. <Note> - If you first used Claude Code before May 6, 2026 and haven't saved a `tui` setting, Claude Code may open a dialog at startup offering the switch. If you accept, Claude Code saves the setting and relaunches the same way `/tui fullscreen` does, carrying the same session state. + If you first used Claude Code before May 6, 2026 and haven't saved a `tui` setting, Claude Code may open a dialog at startup offering the switch. If you accept, Claude Code relaunches the same way `/tui fullscreen` does, carrying the same session state, and saves the setting once the relaunched session has [started successfully](#fullscreen-renderer-didnt-finish-starting). </Note> You can also set the `CLAUDE_CODE_NO_FLICKER` environment variable before starting Claude Code:
CLAUDE_CODE_NO_FLICKER=1 claude ``` -The `tui` setting and the environment variable are equivalent. The `/tui` command clears `CLAUDE_CODE_NO_FLICKER` from the relaunched process so the setting it writes takes effect. +Either one turns fullscreen rendering on. After a [failed fullscreen start](#fullscreen-renderer-didnt-finish-starting), Claude Code still honors the variable but not the setting. The `/tui` command clears `CLAUDE_CODE_NO_FLICKER` from the relaunched process so the setting it writes takes effect. ## What changes
``` On Windows, Claude Code already enables full repaint automatically for background sessions and [agent view](/docs/en/agent-view), so you only need to set the variable for an interactive fullscreen session you launched directly. + +<h3 id="fullscreen-renderer-didnt-finish-starting"> + `Claude Code's fullscreen renderer didn't finish starting last time` appears at startup +</h3> + +If a fullscreen session on this machine crashes before it has started successfully, Claude Code starts your next session in the classic renderer and prints one of two lines. A session has started successfully once it has drawn its first frame and then either stayed up for 10 seconds or you ended it with `/exit`, Ctrl+C, or Ctrl+D. The line you see tells you what Claude Code does after this session: + +* After one failed start, you see `Claude Code's fullscreen renderer didn't finish starting last time on this machine`. Claude Code tries fullscreen rendering again in the next session you start +* After two failed starts, you see `Claude Code's fullscreen renderer has repeatedly failed to start on this machine`. Claude Code keeps using the classic renderer until you update Claude Code or run `/tui fullscreen`, and prints nothing in those later sessions + +To confirm that a failed start is why you're in the classic renderer, run `/tui` with no argument. While a failed start is the reason, the `Current renderer` line says so. + +To keep the classic renderer, run `/tui default`, which saves the `tui` setting without relaunching. To try fullscreen rendering again, run `/tui fullscreen`. If that session doesn't finish starting either, [report the problem](#research-preview). + +Before v2.1.236, Claude Code kept starting sessions in fullscreen rendering after a failed start. + +#### How Claude Code counts failed starts + +* Sessions that count: only sessions that started in fullscreen rendering because your `tui` setting says so, because you accepted the [startup dialog](#enable-fullscreen-rendering), or because your account renders fullscreen by default +* `CLAUDE_CODE_NO_FLICKER=1`: if you set it, Claude Code renders that session fullscreen even after a failed start, and doesn't count it +* Count reset: Claude Code counts failed starts per Claude Code version, and a successful fullscreen start resets the count +* Startup dialog: if you accepted the dialog and the relaunched session crashed, Claude Code prints neither line and doesn't show the dialog again on this Claude Code version ## Research preview
interactive-mode Changed · +23 / -22 lines
### General controls -| Shortcut | Description | Context | -| :------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Ctrl+C` | Interrupt, or clear input | Interrupts a running operation. If nothing is running, the first press clears the prompt input and a second press exits Claude Code | -| `Ctrl+X Ctrl+K` | Stop all running [background subagents](/docs/en/sub-agents#run-subagents-in-foreground-or-background) in this session. Press twice within 3 seconds to confirm | Subagent control | -| `Ctrl+D` | Exit Claude Code session | The first press shows a confirmation hint and a second press within 800ms exits. When the prompt has text, `Ctrl+D` deletes the character after the cursor instead | -| `Ctrl+G` or `Ctrl+X Ctrl+E` | Open in default text editor | Edit your prompt or custom response in your default text editor. `Ctrl+X Ctrl+E` is the readline-native binding. Turn on **Show last response in external editor** in `/config` to prepend Claude's previous reply as `#`-commented context above your prompt; Claude Code strips the comment block when you save | -| `Ctrl+L` | Redraw screen | Forces a full terminal redraw, keeping input and conversation history. Use this to recover if the display becomes garbled or partially blank. In [fullscreen rendering](/docs/en/fullscreen#clear-the-conversation), if you press `Ctrl+L` once, Claude Code redraws the screen and also shows a hint that pressing it again runs `/clear`. If you press it twice within two seconds, Claude Code runs `/clear` and starts a new conversation | -| `Ctrl+O` | Toggle transcript viewer | Shows detailed tool usage and execution, with a timestamp and the model used on each assistant message. Also expands MCP calls, which collapse to a single line like "Called slack 3 times" by default | -| `Ctrl+R` | Reverse search command history | Search through previous commands interactively | -| `Ctrl+V` or `Cmd+V` (iTerm2) or `Alt+V` (Windows and WSL) | Paste image from clipboard | Inserts an `[Image #N]` chip at the cursor so you can reference it positionally in your prompt. On WSL, both `Ctrl+V` and `Alt+V` are bound; use `Alt+V` if your terminal intercepts `Ctrl+V` | -| `Ctrl+B` | Background running tasks | Backgrounds Bash commands and agents. Tmux users press twice | -| `Ctrl+T` | Toggle Claude's task checklist | Show or hide [Claude's to-do checklist](#task-list) in the status area. This is not the background-task view; use [`/tasks`](/docs/en/commands) to see running shells and subagents | -| `Ctrl+S` | Stash or restore prompt | With text in the input, stashes it and clears the prompt. Pressed again on an empty prompt, restores the stashed text, cursor position, and pasted content | -| `Ctrl+Z` | Suspend Claude Code | Unix only. Suspends the process to your shell; run `fg` to resume | -| `Left/Right arrows` | Cycle through dialog tabs | Navigate between tabs in permission dialogs and menus | -| `Up/Down arrows` or `Ctrl+P`/`Ctrl+N` | Move cursor or navigate command history | When the input spans more than one visual row, whether wrapped or multiline, first moves the cursor within the prompt. Once the cursor is on the first or last visual row, pressing again navigates command history. While you have messages queued, `Up` from the first row instead [takes them back](#take-back-what-you-queued) | -| `Esc` | Interrupt Claude, or close a dialog | Stop the current response or tool call mid-turn so you can redirect. Claude keeps the work done so far. If you have [messages queued](#queue-messages-while-claude-works), Claude Code sends them next. When a dialog such as a permission prompt is open, `Esc` closes the dialog rather than interrupting Claude | -| `Esc` + `Esc` | Clear input draft, or rewind | When the prompt input contains text, double `Esc` clears it and saves the draft to history so `Up` recalls it. When the input is empty, double `Esc` opens the [rewind menu](/docs/en/checkpointing) to restore or summarize code and conversation from a previous point | -| `Shift+Tab`, or `Alt+M` on Windows when the Node or Bun runtime doesn't enable VT input mode | Cycle permission modes | Cycle through `default` (labeled Manual in the mode indicator), `acceptEdits`, `plan`, and, when available, `bypassPermissions` and then `auto`. From `auto`, the first press switches to `default`. See [permission modes](/docs/en/permission-modes). | -| `Option+P` (macOS) or `Alt+P` (Windows/Linux) | Switch model | Switch models without clearing your prompt | -| `Option+T` (macOS) or `Alt+T` (Windows/Linux) | Toggle extended thinking | Enable or disable extended thinking mode. Has no effect on Fable 5, which always uses extended thinking. Works on macOS without configuring Option as Meta | -| `Option+O` (macOS) or `Alt+O` (Windows/Linux) | Toggle fast mode | Enable or disable [fast mode](/docs/en/fast-mode) | +| Shortcut | Description | Context | +| :------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Ctrl+C` | Interrupt, or clear input | Interrupts a running operation. If nothing is running, the first press clears the prompt input and a second press exits Claude Code | +| `Ctrl+X Ctrl+K` | Stop all running [background subagents](/docs/en/sub-agents#run-subagents-in-foreground-or-background) in this session. Press twice within 3 seconds to confirm | Subagent control | +| `Ctrl+D` | Exit Claude Code session | The first press shows a confirmation hint and a second press within 800ms exits. When the prompt has text, `Ctrl+D` deletes the character after the cursor instead | +| `Ctrl+G` or `Ctrl+X Ctrl+E` | Open in default text editor | Edit your prompt or custom response in your default text editor. `Ctrl+X Ctrl+E` is the readline-native binding. Turn on **Show last response in external editor** in `/config` to prepend Claude's previous reply as `#`-commented context above your prompt; Claude Code strips the comment block when you save | +| `Ctrl+L` | Redraw screen | Forces a full terminal redraw, keeping input and conversation history. Use this to recover if the display becomes garbled or partially blank. In [fullscreen rendering](/docs/en/fullscreen#clear-the-conversation), if you press `Ctrl+L` once, Claude Code redraws the screen and also shows a hint that pressing it again runs `/clear`. If you press it twice within two seconds, Claude Code runs `/clear` and starts a new conversation | +| `Ctrl+O` | Toggle transcript viewer | Shows detailed tool usage and execution, with a timestamp and the model used on each assistant message. Also expands MCP calls, which collapse to a single line like "Called slack 3 times" by default | +| `Ctrl+R` | Reverse search command history | Search through previous commands interactively | +| `Ctrl+V` or `Cmd+V` (iTerm2) or `Alt+V` (Windows and WSL) | Paste image from clipboard | Inserts an `[Image #N]` chip at the cursor so you can reference it positionally in your prompt. On WSL, both `Ctrl+V` and `Alt+V` are bound; use `Alt+V` if your terminal intercepts `Ctrl+V` | +| `Ctrl+B` | Background running tasks | Backgrounds Bash commands and agents. Tmux users press twice | +| `Ctrl+T` | Toggle Claude's task checklist | Show or hide [Claude's to-do checklist](#task-list) in the status area. This is not the background-task view; use [`/tasks`](/docs/en/commands) to see running shells and subagents | +| `Ctrl+S` | Stash or restore prompt | With text in the input, stashes it and clears the prompt. Pressed again on an empty prompt, restores the stashed text, cursor position, and pasted content | +| `Ctrl+Z` | Suspend Claude Code | Unix only. Suspends the process to your shell; run `fg` to resume | +| `Left/Right arrows` | Cycle through dialog tabs | Navigate between tabs in permission dialogs and menus | +| `Tab` | Accept an autocomplete suggestion, or add a comment to a permission answer | While autocomplete suggestions are showing in the prompt input, accepts the selected suggestion. On most permission prompts, with **Yes** or **No** focused, opens a comment field on that option, and pressing it again closes the field. See [add a comment when you answer a permission prompt](/docs/en/permissions#add-a-comment-when-you-answer-a-permission-prompt) | +| `Up/Down arrows` or `Ctrl+P`/`Ctrl+N` | Move cursor or navigate command history | When the input spans more than one visual row, whether wrapped or multiline, first moves the cursor within the prompt. Once the cursor is on the first or last visual row, pressing again navigates command history. While you have messages queued, `Up` from the first row instead [takes them back](#take-back-what-you-queued) | +| `Esc` | Interrupt Claude, or close a dialog | Stop the current response or tool call mid-turn so you can redirect. Claude keeps the work done so far. If you have [messages queued](#queue-messages-while-claude-works), Claude Code sends them next. When a dialog is open, `Esc` closes the dialog. On a permission prompt, `Esc` declines the action, the same as [**No** without a comment](/docs/en/permissions#add-a-comment-when-you-answer-a-permission-prompt) | +| `Esc` + `Esc` | Clear input draft, or rewind | When the prompt input contains text, double `Esc` clears it and saves the draft to history so `Up` recalls it. When the input is empty, double `Esc` opens the [rewind menu](/docs/en/checkpointing) to restore or summarize code and conversation from a previous point | +| `Shift+Tab`, or `Alt+M` on Windows when the Node or Bun runtime doesn't enable VT input mode | Cycle permission modes | Cycle through `default` (labeled Manual in the mode indicator), `acceptEdits`, `plan`, and, when available, `bypassPermissions` and then `auto`. From `auto`, the first press switches to `default`. See [permission modes](/docs/en/permission-modes). On a file permission prompt, the same key closes an open [comment field](/docs/en/permissions#add-a-comment-when-you-answer-a-permission-prompt). With no field open, it selects the option that allows the action for the rest of the session, when the prompt offers that option | +| `Option+P` (macOS) or `Alt+P` (Windows/Linux) | Switch model | Switch models without clearing your prompt | +| `Option+T` (macOS) or `Alt+T` (Windows/Linux) | Toggle extended thinking | Enable or disable extended thinking mode. Has no effect on Fable 5, which always uses extended thinking. Works on macOS without configuring Option as Meta | +| `Option+O` (macOS) or `Alt+O` (Windows/Linux) | Toggle fast mode | Enable or disable [fast mode](/docs/en/fast-mode) | ### Text editing
keybindings Changed · +13 / -11 lines
Actions available in the `Confirmation` context: -| Action | Default | Description | -| :-------------------------- | :-------- | :--------------------------------------------------------------------------------------------------------------------------------- | -| `confirm:yes` | Y, Enter | Confirm action | -| `confirm:no` | N, Escape | Decline action | -| `confirm:previous` | Up | Previous option | -| `confirm:next` | Down | Next option | -| `confirm:nextField` | Tab | Next field | -| `confirm:previousField` | (unbound) | Previous field | -| `confirm:toggle` | Space | Toggle selection | -| `confirm:cycleMode` | Shift+Tab | Cycle permission modes | -| `confirm:toggleExplanation` | Ctrl+E | Toggle a model-generated [explanation of the command](/docs/en/permissions#permission-system) on Bash and PowerShell permission prompts | +| Action | Default | Description | +| :-------------------------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `confirm:yes` | Y, Enter | Confirm action | +| `confirm:no` | N, Escape | Decline action | +| `confirm:previous` | Up | Previous option | +| `confirm:next` | Down | Next option | +| `confirm:nextField` | Tab | Next field | +| `confirm:previousField` | (unbound) | Previous field | +| `confirm:toggle` | Space | Toggle selection | +| `confirm:cycleMode` | Shift+Tab\* | Cycle permission modes. On a file permission prompt, closes an open [comment field](/docs/en/permissions#add-a-comment-when-you-answer-a-permission-prompt); with no field open, selects the option that allows the action for the rest of the session, when the prompt offers that option | +| `confirm:toggleExplanation` | Ctrl+E | Toggle a model-generated [explanation of the command](/docs/en/permissions#permission-system) on Bash and PowerShell permission prompts | + +\*On Windows without VT mode (Node \<24.2.0/\<22.17.0, Bun \<1.2.23), defaults to Meta+M. ### Permission actions
permissions Changed · +15 / -0 lines
### Add a comment when you answer a permission prompt
To turn the shortcut off, set [`permissionExplainerEnabled`](/docs/en/settings#global-config-settings) to `false` in `~/.claude.json`. +### Add a comment when you answer a permission prompt + +You can attach a note to Claude when you approve or deny a single action. On most permission prompts, including Bash, PowerShell, file, and MCP tool prompts, move to **Yes** or **No** and press `Tab` to open a comment field on that option. WebFetch and browser prompts don't offer the field. The options that allow the action for the rest of the session or save a rule don't take one either. + +With the field open, type the comment and then press one of these keys: + +* `Enter`: submits your answer with the comment attached. If you leave the field empty, Claude Code submits the answer without a comment. +* `Tab`: closes the field without answering. Claude Code keeps the text you typed and still sends it if you answer with that option. +* `Shift+Tab`: on a file prompt, such as an Edit or Write prompt, closes the field the same as `Tab`. Before v2.1.235, pressing `Shift+Tab` inside the field instead selected the option that allows the action for the rest of the session, so Claude Code approved the action for the rest of the session and discarded the comment. + +Claude Code delivers the comment differently depending on how you answered: + +* **Yes**: Claude Code runs the action, then sends your comment to Claude after the result. +* **No**: Claude Code sends your comment to Claude as the reason for the denial, and Claude continues working. If you select **No** without a comment on a prompt from the main conversation, Claude Code stops the turn. + ## Manage permissions You can view and manage Claude Code's tool permissions with `/permissions`. The dialog lists all permission rules and the `settings.json` file each rule comes from. You can open the dialog while Claude is working: when you add or remove a rule, Claude Code applies the change starting with Claude's next tool call in the same turn. Before v2.1.234, Claude Code queued the command until the turn finished.
terminal-config Changed · +1 / -1 lines
If flicker is the only problem and your terminal supports synchronized output but isn't auto-detected, such as Emacs `eat`, set [`CLAUDE_CODE_FORCE_SYNC_OUTPUT=1`](/docs/en/env-vars) to stop the flicker without changing renderers. -Run `/tui fullscreen` to switch and save the preference. Your conversation relaunches intact and future sessions start in fullscreen. You can also set the `CLAUDE_CODE_NO_FLICKER` environment variable before starting Claude Code: +Run `/tui fullscreen` to switch and save the preference. Your conversation relaunches intact and future sessions start in fullscreen unless a [fullscreen start fails](/docs/en/fullscreen#fullscreen-renderer-didnt-finish-starting). You can also set the `CLAUDE_CODE_NO_FLICKER` environment variable before starting Claude Code: <CodeGroup> ```bash Bash and Zsh theme={null}
agent-sdk/custom-tools Changed · +0 / -7 lines
## Related documentation
* To connect to external MCP servers (filesystem, GitHub, Slack) instead of building your own, see [Connect MCP servers](/docs/en/agent-sdk/mcp). * To control which tools run automatically versus requiring approval, see [Configure permissions](/docs/en/agent-sdk/permissions). -## Related documentation - -* [TypeScript SDK Reference](/docs/en/agent-sdk/typescript) -* [Python SDK Reference](/docs/en/agent-sdk/python) -* [MCP Documentation](https://modelcontextprotocol.io) -* [SDK Overview](/docs/en/agent-sdk/overview) -
self-hosted-environments-reference Changed · +1 / -1 lines
* `completed`: the session ended cleanly. This covers the child exiting on its own with code `0`, the session being archived or deleted while the child was still connected, and the runner releasing the slot as a clean handoff: an idle release, a startup timeout, or a server-side deassign the poll loop noticed before the child exited. Increments `sessions_completed_total`. * `failed`: the child exited on its own with a non-zero code, either a crash or a setup failure after spawn. Increments `sessions_failed_total`. -* `interrupted`: the runner terminated the child for an operational reason that's neither a session success nor a runner fault, such as a drain, for example a Kubernetes rolling restart sending `SIGTERM`, the max-lifetime watchdog `--kill-session-after-min`, or the `released=false` backstop: the runner terminates the child after the control plane declines three consecutive idle-release requests, each because a user message was still waiting to be processed. Increments `sessions_interrupted_total`. +* `interrupted`: the runner terminated the child for an operational reason that's neither a session success nor a runner fault, such as a drain or the max-lifetime watchdog `--kill-session-after-min`. A Kubernetes rolling restart sending `SIGTERM` is one example of a drain. Increments `sessions_interrupted_total`. The [`post-session` hook](/docs/en/self-hosted-environments-configuration#post-session)'s `CLAUDE_RUNNER_EXIT_REASON` doesn't use this classification for clean handoffs. The hook reports an idle release, a startup timeout, and a server deassign as `interrupted`, since from the hook's perspective the runner killed the child, while the counters above record those same events as `completed`, since nothing went wrong and the slot was handed back cleanly. If you reconcile hook receipts against `sessions_completed_total` directly, you undercount completions. Use the hook for per-session guarantees and the counters for aggregate rates.
errors Changed · +1 / -1 lines
**What to do:** -* In a session started without those restrictions, run `/tui fullscreen`, or `/tui default` to switch back. Claude Code saves the [`tui` setting](/docs/en/settings#available-settings) there and uses it for every later session +* In a session started without those restrictions, run `/tui fullscreen`, or `/tui default` to switch back. Claude Code saves the [`tui` setting](/docs/en/settings#available-settings) there ## Plugin errors
env-vars Changed · +2 / -2 lines
This page is larger than the 256 KiB this site keeps, so one side of the diff below stops where the stored text does.
| `CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY` | Set to `1` to populate the `/model` picker from your gateway's `/v1/models` endpoint when `ANTHROPIC_BASE_URL` points at an Anthropic-compatible gateway such as LiteLLM, Kong, or an internal proxy. Off by default because gateways backed by a shared API key would otherwise show every user every model the key can access. Discovered models are still filtered by an [`availableModels`](/docs/en/settings#available-settings) allowlist the session receives; deliver the list through [MDM or a managed settings file](/docs/en/settings#settings-files), since [server-managed delivery is not available on gateway configurations](/docs/en/server-managed-settings#platform-availability) | | `CLAUDE_CODE_ENABLE_OPUS_4_7_FAST_MODE` | Removed in v2.1.142, when the [fast mode](/docs/en/fast-mode) default moved from Opus 4.6 to Opus 4.7 | | `CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION` | Set to `false` to disable prompt suggestions (the "Prompt suggestions" toggle in `/config`). These are the grayed-out predictions that appear in your prompt input. Takes precedence over the [`promptSuggestionEnabled`](/docs/en/settings#available-settings) setting. See [Prompt suggestions](/docs/en/interactive-mode#prompt-suggestions) | -| `CLAUDE_CODE_ENABLE_TASKS` | Selects which task-tracking tools Claude Code provides in [sessions that have them](/docs/en/tools-reference#task-tool-availability). By default, Claude Code provides the Task tools `TaskCreate`, `TaskUpdate`, `TaskGet`, and `TaskList`. Set to `0` to get the legacy `TodoWrite` tool instead. See [Task list](/docs/en/interactive-mode#task-list) and [Migrate to Task tools](/docs/en/agent-sdk/todo-tracking#migrate-to-task-tools) | +| `CLAUDE_CODE_ENABLE_TASKS` | Selects which task-tracking tools Claude Code provides in [sessions that have them](/docs/en/tools-reference#task-tool-availability). By default, Claude Code provides the Task tools `TaskCreate`, `TaskUpdate`, `TaskGet`, and `TaskList`. Set to `0` to get the legacy `TodoWrite` tool instead. See [Task list](/docs/en/interactive-mode#task-list) | | `CLAUDE_CODE_ENABLE_TELEMETRY` | Set to `1` to enable OpenTelemetry data collection for metrics and logging. Required before configuring OTel exporters. See [Monitoring](/docs/en/monitoring-usage) | | `CLAUDE_CODE_ENABLE_TODO_TOOLS` | Set to `1` to get the task-tracking tools on the models listed under [Task tool availability](/docs/en/tools-reference#task-tool-availability), where Claude Code otherwise leaves them out. `CLAUDE_CODE_ENABLE_TASKS` still selects the Task tools or `TodoWrite`. Requires Claude Code v2.1.233 or later | | `CLAUDE_CODE_EXIT_AFTER_STOP_DELAY` | Time in milliseconds to wait after the query loop becomes idle before automatically exiting. Useful for automated workflows and scripts using SDK mode |
| `CLAUDE_CODE_MESSAGING_TOKEN` | Set by Claude Code, not by you: in sessions that bind an [inbox socket](/docs/en/cross-session-messaging#the-sessions-inbox-socket), Claude Code exports this per-session token to hooks and Bash commands alongside `CLAUDE_CODE_MESSAGING_SOCKET`. A script posting to the socket can send `{"type":"auth","token":"<token>"}` as its first line to prove it belongs to the session. The [own-child rules](/docs/en/cross-session-messaging#the-sessions-inbox-socket) say when Claude Code consults it. Each session exports its own token, never one inherited from a parent session. Settings `env` blocks can't set it. Requires Claude Code v2.1.228 or later | | `CLAUDE_CODE_NATIVE_CURSOR` | Set to `1` to show the terminal's own cursor at the input caret instead of a drawn block. The cursor respects the terminal's blink, shape, and focus settings | | `CLAUDE_CODE_NEW_INIT` | Set to `1` to make `/init` run an interactive setup flow. The flow asks which files to generate, including CLAUDE.md, skills, and hooks, before exploring the codebase and writing them. Without this variable, `/init` generates a CLAUDE.md automatically without prompting | -| `CLAUDE_CODE_NO_FLICKER` | Set to `1` to enable [fullscreen rendering](/docs/en/fullscreen), a research preview that reduces flicker and keeps memory flat in long conversations. Equivalent to the [`tui`](/docs/en/settings#available-settings) setting; you can also switch with `/tui fullscreen` | +| `CLAUDE_CODE_NO_FLICKER` | Set to `1` to enable [fullscreen rendering](/docs/en/fullscreen), a research preview that reduces flicker and keeps memory flat in long conversations. You can also switch with `/tui fullscreen` | | `CLAUDE_CODE_OAUTH_REFRESH_TOKEN` | OAuth refresh token for Claude.ai authentication. When set, `claude auth login` exchanges this token directly instead of opening a browser. Requires `CLAUDE_CODE_OAUTH_SCOPES`. Useful for provisioning authentication in automated environments | | `CLAUDE_CODE_OAUTH_SCOPES` | Space-separated OAuth scopes the refresh token was issued with, such as `"user:profile user:inference user:sessions:claude_code"`. Required when `CLAUDE_CODE_OAUTH_REFRESH_TOKEN` is set | | `CLAUDE_CODE_OAUTH_TOKEN` | OAuth access token for claude.ai authentication. Alternative to `/login` for SDK and automated environments. Takes precedence over keychain-stored credentials. Generate one with [`claude setup-token`](/docs/en/authentication#generate-a-long-lived-token). Unless you run [`/login`](/docs/en/authentication#authentication-precedence), Claude Code uses the token you set for the whole session. To replace an expired token, generate a new one and restart |
| `CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT` | Set to `1` to use a shorter system prompt and abbreviated tool descriptions on any model. Set to `0`, `false`, `no`, or `off` to opt out even on models where the experiment or server configuration would otherwise enable it. The full tool set, hooks, MCP servers, and CLAUDE.md discovery remain enabled | | `CLAUDE_CODE_SKIP_ANTHROPIC_AWS_AUTH` | Skip client-side authentication for [Claude Platform on AWS](/docs/en/claude-platform-on-aws), for gateways that sign requests themselves | | `CLAUDE_CODE_SKIP_AWS_CRED_CACHE` | Set to `1` to turn off the in-process cache of credentials resolved from the AWS default credential provider chain, so Claude Code resolves the chain on every API request. With the cache off, an SSO-backed profile requests credentials from IAM Identity Center on every request. See [credential caching and resolution timeout](/docs/en/amazon-bedrock#credential-caching-and-resolution-timeout). Requires Claude Code v2.1.207 or later | -| `CLAUDE_CODE_SKIP_BEDROCK_AUTH` | Skip AWS authentication for Amazon Bedrock (for example, when using an LLM gateway) +| `CLAUDE_CODE_SKIP_BEDROCK_AUTH` | Skip AWS authentication for Amazon Bedrock (for example, when using an LLM gateway)
agent-sdk/mcp Changed · +31 / -52 lines
### HTTP/SSE servers -Use HTTP or SSE for cloud-hosted MCP servers and remote APIs: +Use HTTP or SSE for cloud-hosted MCP servers and remote APIs. For the `.mcp.json` form, use the same fields as the example at [HTTP headers for remote servers](#http-headers-for-remote-servers), with `"type": "sse"` for an SSE server. In code, pass the server's URL: -<Tabs> - <Tab title="In code"> - <CodeGroup> - ```typescript TypeScript hidelines={1,-1} theme={null} - const _ = { - options: { - mcpServers: { - "remote-api": { - type: "sse", - url: "https://api.example.com/mcp/sse", - headers: { - Authorization: `Bearer ${process.env.API_TOKEN}` - } - } - }, - allowedTools: ["mcp__remote-api__*"] - } - }; - ``` - - ```python Python theme={null} - options = ClaudeAgentOptions( - mcp_servers={ - "remote-api": { - "type": "sse", - "url": "https://api.example.com/mcp/sse", - "headers": {"Authorization": f"Bearer {os.environ['API_TOKEN']}"}, - } - }, - allowed_tools=["mcp__remote-api__*"], - ) - ``` - </CodeGroup> - </Tab> - - <Tab title=".mcp.json"> - ```json theme={null} - { - "mcpServers": { +<CodeGroup> + ```typescript TypeScript hidelines={1,-1} theme={null} + const _ = { + options: { + mcpServers: { "remote-api": { - "type": "sse", - "url": "https://api.example.com/mcp/sse", - "headers": { - "Authorization": "Bearer ${API_TOKEN}" + type: "sse", + url: "https://api.example.com/mcp/sse", + headers: { + Authorization: `Bearer ${process.env.API_TOKEN}` } } - } + }, + allowedTools: ["mcp__remote-api__*"] } - ``` - </Tab> -</Tabs> + }; + ``` + ```python Python theme={null} + options = ClaudeAgentOptions( + mcp_servers={ + "remote-api": { + "type": "sse", + "url": "https://api.example.com/mcp/sse", + "headers": {"Authorization": f"Bearer {os.environ['API_TOKEN']}"}, + } + }, + allowed_tools=["mcp__remote-api__*"], + ) + ``` +</CodeGroup> + For the streamable HTTP transport, use `"type": "http"` instead. In `.mcp.json` and other JSON config files, `"streamable-http"` is accepted as an alias for `"http"`. The programmatic `mcpServers` option accepts only `"http"`. ### SDK MCP servers
### Tool output exceeds maximum allowed tokens -The SDK applies the same MCP output limit as Claude Code. When a tool result is larger than 25,000 tokens, the full output is saved to a file and the tool result is replaced with an error message that names the file path, so the agent can read the output back in portions. Raise the limit with the [`MAX_MCP_OUTPUT_TOKENS`](/docs/en/env-vars) environment variable. See [MCP output limits and warnings](/docs/en/mcp#mcp-output-limits-and-warnings) for the full behavior, including how a server can declare a higher per-tool limit. +The SDK applies the same MCP output limit as Claude Code. When a tool result is larger than 25,000 tokens, the full output is saved to a file and the tool result is replaced with an error message that names the file path, so the agent can read the output back in portions. Raise the limit with the [`MAX_MCP_OUTPUT_TOKENS`](/docs/en/env-vars) environment variable. See [MCP output limits and warnings](/docs/en/mcp#mcp-output-limits-and-warnings) for the full behavior, including how a server can declare a higher per-tool limit with the `anthropic/maxResultSizeChars` annotation. ## Related resources * **[Custom tools guide](/docs/en/agent-sdk/custom-tools)**: Build your own MCP server that runs in-process with your SDK application * **[Permissions](/docs/en/agent-sdk/permissions)**: Control which MCP tools your agent can use with `allowedTools` and `disallowedTools` -* **[MCP output limits and warnings](/docs/en/mcp#mcp-output-limits-and-warnings)**: How the SDK handles tool results that exceed `MAX_MCP_OUTPUT_TOKENS`, including the persist-to-disk fallback and the `anthropic/maxResultSizeChars` per-tool annotation * **[TypeScript SDK reference](/docs/en/agent-sdk/typescript)**: Full API reference including MCP configuration options * **[Python SDK reference](/docs/en/agent-sdk/python)**: Full API reference including MCP configuration options * **[MCP server directory](https://github.com/modelcontextprotocol/servers)**: Browse available MCP servers for databases, APIs, and more
remote-control Changed · +8 / -4 lines
### "Remote Control isn't enabled for this account" ### "Remote Control is not yet enabled for your account"
> Continue a local Claude Code session from your phone, tablet, or any browser using Remote Control. Works with claude.ai/code and the Claude mobile app. <Note> - Remote Control is in research preview and available on all plans. On Team and Enterprise, it is off by default until an Owner enables the Remote Control toggle in [Claude Code admin settings](https://claude.ai/admin-settings/claude-code). + Remote Control is available on all plans. On Team and Enterprise, it is off by default until an Owner enables the Remote Control toggle in [Claude Code admin settings](https://claude.ai/admin-settings/claude-code). </Note> Remote Control connects [claude.ai/code](https://claude.ai/code) or the Claude app for [iOS](https://apps.apple.com/us/app/claude-by-anthropic/id6473753684) and [Android](https://play.google.com/store/apps/details?id=com.anthropic.claude) to a Claude Code session running on your machine. Start a task at your desk, then pick it up from your phone on the couch or a browser on another computer.
Your cached account information is stale or incomplete. Run `claude auth login` to refresh it. -### "Remote Control is not yet enabled for your account" +### "Remote Control isn't enabled for this account" -The Remote Control rollout has not reached your account, or your cached entitlements are out of date. If you recently changed plans, run `claude auth logout` then `claude auth login` to refresh them. Run `claude doctor` to see which individual eligibility check failed. Environment-variable conflicts, unreachable checks, and organization policy each produce their own message, so this error means the rollout gate itself. Before v2.1.154, a variable that disables feature-flag evaluation, such as `DISABLE_TELEMETRY` or `DO_NOT_TRACK`, also produced this message; the "Remote Control requires feature-flag evaluation" entry below covers that configuration. +Claude Code checked Remote Control availability for the account you're signed in with and the check came back off. The usual cause is cached entitlements that are out of date after a plan change. Run `claude auth logout` then `claude auth login` to refresh them, and update Claude Code if you're on an old version. + +Run `claude doctor` to see which individual eligibility check failed. Environment-variable conflicts, unreachable checks, and your organization's Remote Control setting each produce their own message, so this error means the account-level check itself. + +Before v2.1.239, this message read "Remote Control is not yet enabled for your account". Before v2.1.154, a variable that disables feature-flag evaluation, such as `DISABLE_TELEMETRY` or `DO_NOT_TRACK`, also produced this message; the "Remote Control requires feature-flag evaluation" entry below covers that configuration. ### "Couldn't verify Remote Control eligibility"
self-hosted-environments-configuration Changed · +10 / -1 lines
#### Hook timing when the runner releases a session
* `completed`: a clean exit, including a session archived or deleted while the child was still connected. * `failed`: a child crash or a setup failure after spawn. -* `interrupted`: an idle release, startup timeout, server deassign, drain, watchdog kill, or the [`released=false` backstop](/docs/en/self-hosted-environments-reference#session-lifecycle-counter-semantics). +* `interrupted`: an idle release, startup timeout, server deassign, drain, or watchdog kill. * `abandoned`: reserved for sessions another runner claimed; the hook doesn't currently fire in that case. The [session lifecycle counter semantics](/docs/en/self-hosted-environments-reference#session-lifecycle-counter-semantics) classify an idle release, a startup timeout, and a server deassign as `completed` instead: those are clean handoffs from the session's perspective even though this hook reports them as `interrupted`.
``` The hook pushes with whatever git credentials are available in its own environment on the runner host. Under the [no-credentials-in-the-image posture](/docs/en/self-hosted-environments-deploy#configure-git), including when the built-in clone goes through the Anthropic git proxy, there are none, so mint a short-lived push credential inside the hook before pushing: exchange the session token the hook receives in `CLAUDE_CODE_SESSION_ACCESS_TOKEN` with your own token service, verifying it as [Verify session identity](/docs/en/self-hosted-environments-identity) describes. When the hook holds a credential the session didn't, also pin where it pushes: replace `origin` with an operator-supplied URL and pass `-c credential.helper=` plus your own helper, so repo-local config the session wrote can't redirect the credentialed push. + +#### Hook timing when the runner releases a session + +A released session can resume on another runner. On a runner on v2.1.236 or later, what the session was doing at release decides whether it can resume before this hook finishes: + +* **Idle after a turn, or timed out at startup**: the runner stops the child and runs this hook to completion. Only then does it release the session. A user message sent while the hook runs can't resume the session on another runner before the hook finishes. +* **Waiting for the user to answer a prompt, such as a permission prompt**: the runner releases the session first, then runs this hook. A user message sent while the hook runs can resume the session on another runner before the hook finishes. + +A release at the [`--retire-at`](/docs/en/self-hosted-environments-reference#runner-cli-flags) time follows the same two paths. During a `SIGTERM` drain, the runner holds the session lease until the hook finishes; see [Shutdown timing](/docs/en/self-hosted-environments-deploy#shutdown-timing). Before v2.1.236, the runner released the session first and then ran this hook on both paths. ### command
agent-sdk/python Changed · +1 / -1 lines
On other models, Claude Code provides the Task tools by default and `TodoWrite` only when you set `CLAUDE_CODE_ENABLE_TASKS=0`. - See [Model availability](/docs/en/agent-sdk/todo-tracking#model-availability) to opt in and [Migrate to Task tools](/docs/en/agent-sdk/todo-tracking#migrate-to-task-tools) to update your monitoring code. + See [Model availability](/docs/en/agent-sdk/todo-tracking#model-availability) to opt in. </Note> **Input:**