Register and share your invite link to earn from video plays and referrals.

Search results for ClaudeAgentSDK
ClaudeAgentSDK community
One keyword maps to one global community path.
Create community
People
Not Found
Tweets including ClaudeAgentSDK
# Useful but Little-Known Features of Claude Agent SDK 🌍 Want to send messages while the agent is working? Streaming input mode enables interactive sessions! With streaming input mode, you can add messages, interrupt execution, and send images during an active session. 📌 Title: Streaming Input Mode 🔗 URL: 🧩 Overview Streaming input mode (the recommended, preferred mode) provides a persistent, interactive session using `AsyncGenerator`. Unlike single message input (one-shot), it supports message queueing, image attachments, and mid-execution interruption during a session. Messages are sent sequentially via `yield`, and follow-up messages can be dynamically generated based on conditions — ideal for chat interfaces and complex workflows. 🛠 How to Use ```python # Python - Interactive session with streaming input from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, AssistantMessage, TextBlock import base64 async def message_generator(): yield { "type": "user", "message": {"role": "user", "content": "Analyze for security issues"}, } # Follow-up with image with open("diagram.png", "rb") as f: image_data = base64.b64encode( yield { "type": "user", "message": { "role": "user", "content": [ {"type": "text", "text": "Also review this architecture diagram"}, {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": image_data}}, ], }, } options = ClaudeAgentOptions(max_turns=10, allowed_tools=["Read", "Grep"]) async with ClaudeSDKClient(options) as client: await client.query(message_generator()) async for message in client.receive_response(): if isinstance(message, AssistantMessage): for block in message.content: if isinstance(block, TextBlock): print(block.text) ``` ```typescript // TypeScript - Send messages sequentially via AsyncGenerator import { query, type SDKUserMessage } from "@anthropic-ai/claude-agent-sdk"; async function* generateMessages(): AsyncGenerator { yield { type: "user", message: { role: "user", content: "Analyze this codebase for security issues" }, parent_tool_use_id: null, }; // Dynamic follow-up based on conditions await new Promise((resolve) => setTimeout(resolve, 2000)); yield { type: "user", message: { role: "user", content: "Now focus on authentication" }, parent_tool_use_id: null, }; } for await (const message of query({ prompt: generateMessages(), options: { maxTurns: 10, allowedTools: ["Read", "Grep"] } })) { if (message.type === "result" && message.subtype === "success") { console.log(message.result); } } ``` 🏗 Integration into Production Systems - Wire chat UI message sends to the generator's `yield` to pass user input to the agent in real time - Include `base64`-encoded image uploads in messages for visual analysis capabilities - Send interrupt signals to redirect the agent, enabling control over long-running tasks - Context is naturally maintained within the session, eliminating multi-turn conversation management overhead 💡 Use Cases 💬 Build interactive sessions between users and agents in custom chatbots 🖼 Dynamically send screenshots or diagrams during code review for analysis 🔄 Send additional instructions or shift focus areas during long-running code analysis ⚠️ Caveats - Single message input does not support image attachments, dynamic message queueing, or real-time interruption - For stateless environments (Lambda functions, etc.), use single message input instead - In Python, streaming input requires the `ClaudeSDKClient` context manager ✨ The real power of AI agents goes beyond one-shot queries. Build rich interactive experiences with streaming input! #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 Staring at a blank screen while the agent works? Real-time streaming fixes that! Enable `include_partial_messages` to receive text and tool call chunks as they're generated. 📌 Title: Real-Time Partial Messages 🔗 URL: 🧩 Overview Setting `include_partial_messages` (Python) / `includePartialMessages` (TypeScript) to `true` causes the SDK to emit `StreamEvent` messages alongside regular `AssistantMessage` objects. `StreamEvent` contains raw Claude API streaming events — `text_delta` for text chunks and `input_json_delta` for tool input fragments. This enables responsive UIs with typing-style text display and tool execution status indicators. 🛠 How to Use ```python # Python - Display text chunks in real time from claude_agent_sdk import query, ClaudeAgentOptions from claude_agent_sdk.types import StreamEvent options = ClaudeAgentOptions(include_partial_messages=True) async for message in query(prompt="Explain how databases work", options=options): if isinstance(message, StreamEvent): event = message.event if event.get("type") == "content_block_delta": delta = event.get("delta", {}) if delta.get("type") == "text_delta": print(delta.get("text", ""), end="", flush=True) ``` ```typescript // TypeScript - Stream tool calls with status indicators import { query } from "@anthropic-ai/claude-agent-sdk"; let currentTool: string | null = null; for await (const message of query({ prompt: "Read the README.md file", options: { includePartialMessages: true } })) { if (message.type === "stream_event") { const event = message.event; if (event.type === "content_block_start" && event.content_block.type === "tool_use") { currentTool = event.content_block.name; process.stdout.write(`\n[Using ${currentTool}...]`); } else if (event.type === "content_block_delta" && === "text_delta") { process.stdout.write( } else if (event.type === "content_block_stop" && currentTool) { console.log(" done"); currentTool = null; } } } ``` 🏗 Integration into Production Systems - Append `text_delta` chunks to message bubbles in chat UIs for typing-style rendering - Detect tool names from `content_block_start` (type: `tool_use`) events and show "running..." spinners - Track message boundaries with `message_start`/`message_stop` events - Text deltas must be accumulated manually — prepare an accumulator buffer 💡 Use Cases 💬 Implement ChatGPT-style real-time typing display in custom UIs 🔧 Show the currently active tool name and progress in a status bar 📝 Start displaying long analysis results before the full response is complete ⚠️ Caveats - `StreamEvent` events are raw Claude API events, not accumulated text — you must concatenate text deltas yourself - Structured output (`structured_output`) is not sent as streaming deltas; it only appears in the final `ResultMessage` - UI state management is needed — e.g., pause text streaming while a tool is executing (track an `in_tool` flag) ✨ No more "Processing, please wait..." screens. Partial messages bring users closer to the agent's work in real time! #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 What if your agent tries to delete files on its own? Runtime approval gives you safe control! The `canUseTool` callback lets you approve, deny, or modify tool inputs in real time before execution. 📌 Title: Runtime Approval via canUseTool Callback 🔗 URL: 🧩 Overview `canUseTool` is a callback function passed in query options, fired at the last step (6th) of the permission evaluation flow. It never fires for tool calls auto-approved at an earlier step — by an allow rule or a mode like `acceptEdits` or `bypassPermissions` — so use a `PreToolUse` hook for logic that must apply to every tool call. The callback receives the tool name and input parameters. You return `allow` (with original or modified input) or `deny` (with an explanatory message). This enables dynamic control — sandboxing paths, blocking dangerous commands, or requesting user confirmation through your UI. It is skipped in `dontAsk` mode. 🛠 How to Use ```python # Python - Tool approval callback from claude_agent_sdk import ClaudeAgentOptions, query from claude_agent_sdk.types import PermissionResultAllow, PermissionResultDeny, HookMatcher async def can_use_tool(tool_name, input_data, context): print(f"\nTool: {tool_name}") if tool_name == "Bash": print(f"Command: {input_data.get('command')}") # Block rm commands and suggest archiving if "rm" in input_data.get("command", ""): return PermissionResultDeny( message="Please archive instead of deleting" ) response = input("Allow this action? (y/n): ") if response.lower() == "y": return PermissionResultAllow(updated_input=input_data) return PermissionResultDeny(message="User denied this action") # Dummy hook (required for Python streaming mode) async def dummy_hook(input_data, tool_use_id, context): return {"continue_": True} ``` ```typescript // TypeScript - Modify input before allowing import { query } from "@anthropic-ai/claude-agent-sdk"; for await (const message of query({ prompt: "Clean up temporary files", options: { canUseTool: async (toolName, input) => { if (toolName === "Bash") { // Rewrite paths to sandbox const sandboxed = { ...input, command: input.command.replace("/tmp", "/tmp/sandbox") }; return { behavior: "allow", updatedInput: sandboxed }; } return { behavior: "allow", updatedInput: input }; } } })) { /* ... */ } ``` 🏗 Integration into Production Systems - Display tool approval dialogs in web UIs and return user decisions to the callback - Use `context.suggestions` to retrieve `PermissionUpdate` entries for persistent "always allow" rules - Auto-block dangerous operations (`rm`, `DROP TABLE`, etc.) and suggest safe alternatives in the deny message - Sanitize inputs (restrict paths, override parameters) to dynamically control agent scope 💡 Use Cases 🔒 Require approval for write commands to production databases 📁 Restrict file operations to specific directories via dynamic path rewriting 👥 Control tool access based on user permission levels in multi-user environments ⚠️ Caveats - In Python, `canUseTool` requires streaming mode and a `PreToolUse` hook configuration - In `dontAsk` mode, the callback is skipped; use hooks for security-critical restrictions - The callback pauses execution indefinitely until a response is returned; use the `defer` hook decision for long-running cases ✨ It's not "full automation" or "full manual" — canUseTool enables smart operation where humans decide only at critical points! #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 Tired of agents making decisions without asking? Guide them interactively with multiple-choice questions! The `AskUserQuestion` tool in Claude Agent SDK lets agents ask clarifying questions with predefined choices. 📌 Title: Multiple-Choice Clarifying Questions via AskUserQuestion 🔗 URL: 🧩 Overview When multiple valid approaches exist, the agent calls the `AskUserQuestion` tool to ask users for direction. Each question includes 2-4 options (with `label` + `description`), supporting both single and multi-select. Questions are handled via the `canUseTool` callback, processed in-loop without ending the query call. This is especially common in `plan` mode, where Claude explores the codebase and asks questions before proposing a plan. 🛠 How to Use ```python # Python - Handle clarifying questions in the callback from claude_agent_sdk import ClaudeAgentOptions, query from claude_agent_sdk.types import PermissionResultAllow, HookMatcher async def can_use_tool(tool_name, input_data, context): if tool_name == "AskUserQuestion": answers = {} for q in input_data.get("questions", []): print(f"\n{q['header']}: {q['question']}") for i, opt in enumerate(q["options"]): print(f" {i+1}. {opt['label']} - {opt['description']}") choice = input("Your choice: ").strip() # Answer by number or free text try: idx = int(choice) - 1 answers[q["question"]] = q["options"][idx]["label"] except (ValueError, IndexError): answers[q["question"]] = choice return PermissionResultAllow( updated_input={"questions": input_data["questions"], "answers": answers} ) return PermissionResultAllow(updated_input=input_data) ``` ```typescript // TypeScript - Handle AskUserQuestion import { query } from "@anthropic-ai/claude-agent-sdk"; for await (const message of query({ prompt: "Help me decide on a tech stack", options: { tools: ["Read", "Grep", "AskUserQuestion"], canUseTool: async (toolName, input) => { if (toolName === "AskUserQuestion") { const answers: Record = {}; for (const q of input.questions) { // Display options in UI and collect user selection answers[q.question] = selectedLabel; } return { behavior: "allow", updatedInput: { questions: input.questions, answers } }; } return { behavior: "allow", updatedInput: input }; } } })) { /* ... */ } ``` 🏗 Integration into Production Systems - In web UIs, display questions and options as modal dialogs and return user answers to the callback - When specifying a `tools` array, include `"AskUserQuestion"` or the clarifying question feature will be disabled - For `multiSelect: true` questions, return multiple answers as a comma-separated string or array - Free-text answers (beyond predefined options) can be returned directly as the value 💡 Use Cases 🎯 Let agents ask about framework and database preferences during tech stack decisions 📐 Confirm output format or architecture patterns before code generation 🔀 When multiple refactoring approaches exist, let users choose the one matching their intent ⚠️ Caveats - Each `AskUserQuestion` call supports 1-4 questions with 2-4 options each - `AskUserQuestion` is not currently available in subagents spawned via the Agent tool - The callback waits indefinitely until an answer is returned; use the `defer` hook decision if timeouts are needed ✨ The best AI assistant doesn't just guess — it asks the right questions at the right moments! #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 Tired of agents making decisions without asking? Guide them interactively with multiple-choice questions! The `AskUserQuestion` tool in Claude Agent SDK lets agents ask clarifying questions with predefined choices. 📌 Title: Multiple-Choice Clarifying Questions via AskUserQuestion 🔗 URL: 🧩 Overview When multiple valid approaches exist, the agent calls the `AskUserQuestion` tool to ask users for direction. Each question includes 2-4 options (with `label` + `description`), supporting both single and multi-select. Questions are handled via the `canUseTool` callback, processed in-loop without ending the query call. This is especially common in `plan` mode, where Claude explores the codebase and asks questions before proposing a plan. 🛠 How to Use ```python # Python - Handle clarifying questions in the callback from claude_agent_sdk import ClaudeAgentOptions, query from claude_agent_sdk.types import PermissionResultAllow, HookMatcher async def can_use_tool(tool_name, input_data, context): if tool_name == "AskUserQuestion": answers = {} for q in input_data.get("questions", []): print(f"\n{q['header']}: {q['question']}") for i, opt in enumerate(q["options"]): print(f" {i+1}. {opt['label']} - {opt['description']}") choice = input("Your choice: ").strip() # Answer by number or free text try: idx = int(choice) - 1 answers[q["question"]] = q["options"][idx]["label"] except (ValueError, IndexError): answers[q["question"]] = choice return PermissionResultAllow( updated_input={"questions": input_data["questions"], "answers": answers} ) return PermissionResultAllow(updated_input=input_data) ``` ```typescript // TypeScript - Handle AskUserQuestion import { query } from "@anthropic-ai/claude-agent-sdk"; for await (const message of query({ prompt: "Help me decide on a tech stack", options: { tools: ["Read", "Grep", "AskUserQuestion"], canUseTool: async (toolName, input) => { if (toolName === "AskUserQuestion") { const answers: Record = {}; for (const q of input.questions) { // Display options in UI and collect user selection answers[q.question] = selectedLabel; } return { behavior: "allow", updatedInput: { questions: input.questions, answers } }; } return { behavior: "allow", updatedInput: input }; } } })) { /* ... */ } ``` 🏗 Integration into Production Systems - In web UIs, display questions and options as modal dialogs and return user answers to the callback - When specifying a `tools` array, include `"AskUserQuestion"` or the clarifying question feature will be disabled - For `multiSelect: true` questions, return multiple answers as a comma-separated string or array - Free-text answers (beyond predefined options) can be returned directly as the value 💡 Use Cases 🎯 Let agents ask about framework and database preferences during tech stack decisions 📐 Confirm output format or architecture patterns before code generation 🔀 When multiple refactoring approaches exist, let users choose the one matching their intent ⚠️ Caveats - Each `AskUserQuestion` call supports 1-4 questions with 2-4 options each - `AskUserQuestion` is not currently available in subagents spawned via the Agent tool - The callback waits indefinitely until an answer is returned; use the `defer` hook decision if timeouts are needed ✨ The best AI assistant doesn't just guess — it asks the right questions at the right moments! #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 Do you really know how much your agent runs cost? Detailed tracking makes it visible! Claude Agent SDK provides granular token usage and cost breakdowns for every query. 📌 Title: Detailed Cost and Usage Tracking 🔗 URL: 🧩 Overview `ResultMessage` includes `total_cost_usd` (estimated cost), `usage` (token breakdown), and `num_turns` (turn count), available on all result subtypes including errors. Additionally, `model_usage` (Python) / `modelUsage` (TypeScript) provides per-model cost and token breakdowns. When parallel tool calls occur, messages share the same ID with duplicate usage data, so ID-based deduplication is essential for accurate counting. 🛠 How to Use ```python # Python - Get total cost for a query from claude_agent_sdk import query, ResultMessage async for message in query(prompt="Summarize this project"): if isinstance(message, ResultMessage): print(f"Total cost: ${ or 0}") # Per-model breakdown if message.model_usage: for model, usage in message.model_usage.items(): print(f" {model}: ${usage['costUSD']:.4f}") print(f" Input tokens: {usage['inputTokens']}") print(f" Cache read: {usage['cacheReadInputTokens']}") ``` ```typescript // TypeScript - Accumulate costs across multiple queries import { query } from "@anthropic-ai/claude-agent-sdk"; let totalSpend = 0; for (const prompt of prompts) { for await (const message of query({ prompt })) { if (message.type === "result") { totalSpend += // Per-model breakdown for (const [model, usage] of Object.entries(message.modelUsage)) { console.log(`${model}: $${usage.costUSD.toFixed(4)}`); } } } } console.log(`Total: $${totalSpend.toFixed(4)}`); ``` 🏗 Integration into Production Systems - Send `total_cost_usd` to monitoring systems for real-time cost trend visualization - Analyze per-model costs via `model_usage` to optimize subagent cost allocation - Calls that `resume` the same session already include the session's earlier spend (Claude Code v2.1.277 and later), so read the latest result rather than summing, which double-counts; implement summation logic only for independent calls that share no session - Errors still incur costs, so always record costs from failed `ResultMessage` instances too 💡 Use Cases 💰 Report per-user usage costs in multi-tenant environments 📊 Analyze per-model cost breakdowns to find optimal model configurations 🔍 Monitor cache token ratios (`cache_read_input_tokens`) to measure prompt caching effectiveness ⚠️ Caveats - `total_cost_usd` is a client-side estimate and may differ from actual billing. Use the Usage and Cost API for authoritative billing data - Parallel tool calls produce duplicate messages with the same ID; deduplicate by ID to avoid inflated token counts - Setting `ENABLE_PROMPT_CACHING_1H` enables 1-hour TTL caching but increases write costs ✨ No cost optimization without cost visibility. Start by integrating tracking to understand your agent's spending patterns! #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 Losing track of complex multi-step tasks? Structured task tracking makes progress visible! Claude Agent SDK includes built-in task management for organized progress tracking during agent execution. 📌 Title: Structured Task (Todo) Tracking 🔗 URL: 🧩 Overview Four tools — `TaskCreate`, `TaskUpdate`, `TaskGet`, and `TaskList` — enable structured task management during agent execution. These task-tracking tools are available by default only on Claude 3.x models, Opus 4 through 4.7, Sonnet 4 through 4.6, and Haiku 4.5 (the default set in Claude Code v2.1.268 and later, bundled by the TypeScript SDK from v0.3.268); on every other model you must opt the session in. The agent automatically registers multi-step work as tasks and manages their lifecycle: `pending` → `in_progress` → `completed`. Unlike the legacy `TodoWrite` which overwrote the entire list on every call, Task tools operate on individual items, enabling fine-grained progress tracking. 🛠 How to Use ```python # Python - Monitor TaskCreate/TaskUpdate in the stream from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock async for message in query( prompt="Optimize my React app performance", # Keeps the Task tools on models where Claude Code otherwise doesn't provide them options=ClaudeAgentOptions(env={"CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"}), ): if not isinstance(message, AssistantMessage): continue for block in message.content: if not isinstance(block, ToolUseBlock): continue if == "TaskCreate": print(f"+ {block.input['subject']}") elif == "TaskUpdate" and block.input.get("status"): # The streamed input is the raw shape the model emitted (may be id / task_id) task_id = ( block.input.get("taskId") or block.input.get("id") or block.input.get("task_id") ) print(f" {task_id} -> {block.input['status']}") ``` ```typescript // TypeScript - Display task creation and updates in real time import { query } from "@anthropic-ai/claude-agent-sdk"; for await (const message of query({ prompt: "Optimize my React app performance", // Keeps the Task tools on models where Claude Code otherwise doesn't provide them options: { env: { ...process.env, CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } }, })) { if (message.type !== "assistant") continue; for (const block of message.message.content) { if (block.type !== "tool_use") continue; if ( === "TaskCreate") { console.log(`+ ${block.input.subject}`); } else if ( === "TaskUpdate") { // The streamed input is the raw shape the model emitted (may be id / task_id) const taskId = block.input.taskId ?? ?? block.input.task_id; if (taskId && block.input.status) console.log(` ${taskId} -> ${block.input.status}`); } } } ``` 🏗 Integration into Production Systems - Reflect task progress in UI progress bars or checklists to give users visibility into agent work - Capture `taskId` from `TaskCreate` tool results and maintain a map for a complete task overview - Monitor `TaskList` tool results for snapshots to display on dashboards - Tasks are automatically created for 3+ step workflows, making them ideal for monitoring long-running operations 💡 Use Cases 📋 Share large-scale refactoring progress with the team in real time 🔄 Track completion status of each agent step in CI/CD pipelines 📊 Display which analyses are complete on a dashboard during multi-step code review ⚠️ Caveats - `TaskCreate` input does not contain `taskId`; retrieve it from the corresponding `tool_result` block as `{ task: { id, subject } }` - On models that don't have the tools by default, opt the session in by naming a tool in `allowed_tools`, listing the tools in the `tools` option, or setting `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` in `env` — without opting in, no `tool_use` blocks for them appear in the stream. Conversely, `CLAUDE_CODE_ENABLE_TASKS=0` makes Claude Code provide the legacy `TodoWrite` instead of the four Task tools - Setting `status` to `"deleted"` removes a task ✨ Waiting for multi-step work without knowing what's happening is stressful. Use task tracking to make your agent's work fully transparent! #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 Grant your agent access to files outside the working directory with the additionalDirectories option. Essential for monorepos, shared libraries, and any project spanning multiple directory trees. 📌 Title: Granting Access Beyond the Working Directory 🔗 URL: 🧩 Overview `additionalDirectories` is a `query()` option that allows agents to access paths outside the working directory (cwd). By default, agents can only operate on files within cwd. When you specify additional directories, the agent gains read/write access to files in those paths as well. In `acceptEdits` permission mode, edits within additional directories are also auto-approved. This is especially useful for monorepo packages, shared libraries, or cross-project workflows. 🛠 Usage Pass `add_dirs` (TypeScript: `additionalDirectories`) in the query options. ```python from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage # Grant access to multiple monorepo packages async for message in query( prompt="Update the shared utility functions and fix the imports in the web app", options=ClaudeAgentOptions( add_dirs=[ "/path/to/monorepo/packages/shared-utils", "/path/to/monorepo/packages/web-app", ], permission_mode="acceptEdits", # Auto-approve edits in additional dirs too allowed_tools=["Read", "Edit", "Write", "Grep", "Glob"], ), ): if isinstance(message, ResultMessage) and message.subtype == "success": print(message.result) # Access a shared library alongside the main project async for message in query( prompt="Check the shared library API and update our integration code", options=ClaudeAgentOptions( add_dirs=[ "/path/to/shared-library", ], allowed_tools=["Read", "Edit", "Grep", "Glob"], ), ): if isinstance(message, ResultMessage) and message.subtype == "success": print(message.result) ``` 🏗 Integration into Production Systems - In monorepo setups, list related package paths in `add_dirs` to enable cross-package changes with dependency awareness - Combined with `acceptEdits` mode, file edits (Edit, Write) and filesystem operations (mkdir, rm, mv, cp) in additional directories are auto-approved - Writes to protected paths still prompt even when included in additional directories 💡 Use Cases 📦 Monorepo development: modify shared packages and individual apps simultaneously 📚 Shared library reference: read external library source to verify correct API usage while coding 🔧 Centralized config management: access and update configuration directories outside the project ⚠️ Caveats - Access to paths outside both cwd and additional directories remains blocked or prompted - `bypassPermissions` mode approves all paths regardless of `add_dirs` settings - This expands the agent's security boundary — specify only the minimum necessary paths - `acceptEdits` auto-approval is scoped to cwd and additional directories only ✨ additionalDirectories enables agents to work seamlessly across multiple directory trees, making cross-project and monorepo workflows practical. #ClaudeAgentSDK# #AIAgent#
Show more
# Useful but Little-Known Features of Claude Agent SDK 🌍 Define custom functions as agent tools running in-process using the @tool decorator and create_sdk_mcp_server. Give your agents access to databases, external APIs, and domain-specific logic without managing separate processes. 📌 Title: In-Process Custom Tools (create_sdk_mcp_server / @tool) 🔗 URL: 🧩 Overview Custom tools let you define your own functions that Claude can call during conversations. In Python, use the `@tool` decorator; in TypeScript, use the `tool()` helper. Define a name, description, input schema, and async handler, then wrap tools in `create_sdk_mcp_server` and pass them to `query()`. Tools run in-process — no separate process needed. Tool names follow the `mcp__{server_name}__{tool_name}` convention. Use `readOnlyHint` annotations to enable parallel execution, `isError` for recoverable failures, and return images (base64), resources, or structured content. 🛠 Usage Define tools with the `@tool` decorator and bundle them into an in-process MCP server. ```python from typing import Any import httpx from claude_agent_sdk import tool, create_sdk_mcp_server, query, ClaudeAgentOptions, ResultMessage @tool( "get_temperature", "Get the current temperature at a location", {"latitude": float, "longitude": float}, ) async def get_temperature(args: dict[str, Any]) -> dict[str, Any]: async with httpx.AsyncClient() as client: response = await client.get( "", params={ "latitude": args["latitude"], "longitude": args["longitude"], "current": "temperature_2m", }, ) data = response.json() return { "content": [ {"type": "text", "text": f"Temperature: {data['current']['temperature_2m']}"} ] } # Wrap in an in-process MCP server weather_server = create_sdk_mcp_server( name="weather", version="1.0.0", tools=[get_temperature], ) # Pass to query() async for message in query( prompt="What's the temperature in Tokyo?", options=ClaudeAgentOptions( mcp_servers={"weather": weather_server}, allowed_tools=["mcp__weather__get_temperature"], ), ): if isinstance(message, ResultMessage) and message.subtype == "success": print(message.result) ``` 🏗 Integration into Production Systems - Return `{"is_error": True}` instead of throwing exceptions to keep the agent loop alive and let Claude attempt recovery - Set `readOnlyHint=True` on side-effect-free tools to enable parallel execution with other read-only tools - Return images via `{"type": "image", "data": base64_str, "mimeType": "image/png"}` content blocks - Use `structuredContent` to return machine-readable JSON alongside content (note: not supported by Python `@tool` — requires standalone MCP server) 💡 Use Cases 🗄 Database access: let agents execute DB queries directly 🌐 External API integration: expose internal APIs or third-party services as tools 📊 Data visualization: generate charts and return them as base64 images 🔧 Domain logic: encapsulate calculations, conversions, and validations as callable tools ⚠️ Caveats - Python dict schema treats all keys as required; for optional parameters, omit from schema, describe in the description, and read with `args.get()` - `structuredContent` is not forwarded by Python's `@tool` decorator (use a standalone MCP server) - Tool search is on by default and defers SDK MCP tool schemas; with it disabled, every tool in the `tools` array consumes context on every turn - Annotations are metadata, not enforcement — a `readOnlyHint=True` tool can still write if the handler does so ✨ In-process custom tools let you freely extend agent capabilities with your own functions, without the overhead of managing external processes. #ClaudeAgentSDK# #AIAgent#
Show more
# Practical ways to use the Claude Agent SDK 📝 Customize system prompts flexibly with three levels: preset, append, and full replacement. System Prompt Modification offers three levels of customization via `systemPrompt`: Claude Code preset, append, and custom string replacement. 📌 Title: Modifying System Prompts 🔗 URL: 🧩 Overview Use `preset: "claude_code"` for the full Claude Code prompt, `append` to add to the preset, or a custom string for complete replacement. Output style files enable cross-CLI/SDK persona reuse. 🛠 How to use it `system_prompt` accepts three forms: preset with `{"type": "preset", "preset": "claude_code"}`, append with `"append": "extra instructions"`, or a custom string for full replacement. Use `excludeDynamicSections: true` for cross-session prompt cache sharing. 🏗 Practical usage - For coding agents, use `preset: "claude_code"` for the full prompt with tool guidance and safety rules. - Append team conventions like "Always add docstrings and type hints to Python" — the safest customization that removes nothing. - For support bots or data analysis assistants with unique personas, use a custom string for complete replacement. - Use `excludeDynamicSections: true` to share prompt cache across users/machines and reduce fleet costs. 💡 Use cases 🤖 Claude Code-compatible coding agents 📋 Automatic team convention enforcement 🎭 Custom persona agents ⚠️ Watch out When using custom string replacement, you must provide your own tool guidance and safety instructions. `excludeDynamicSections` requires TS v0.2.98+ / Python v0.1.58+. #ClaudeAgentSDK# #AI#
Show more