Langsung ke konten utama

Instalasi

pip install claude-agent-sdk

Memilih antara query() dan ClaudeSDKClient

Python SDK menyediakan dua cara untuk berinteraksi dengan Claude Code:

Perbandingan cepat

Fiturquery()ClaudeSDKClient
SesiMembuat sesi baru secara defaultMenggunakan kembali sesi yang sama
PercakapanPertukaran tunggalBeberapa pertukaran dalam konteks yang sama
KoneksiDikelola secara otomatisKontrol manual
Streaming Input✅ Didukung✅ Didukung
Interrupts❌ Tidak didukung✅ Didukung
Hooks✅ Didukung✅ Didukung
Custom Tools✅ Didukung✅ Didukung
Continue ChatManual melalui continue_conversation atau resume✅ Otomatis
Use CaseTugas sekali jalanPercakapan berkelanjutan

Kapan menggunakan query() (tugas sekali jalan)

Terbaik untuk:
  • Pertanyaan sekali jalan di mana Anda tidak memerlukan riwayat percakapan
  • Tugas independen yang tidak memerlukan konteks dari pertukaran sebelumnya
  • Skrip otomasi sederhana
  • Ketika Anda menginginkan awal yang segar setiap kali

Kapan menggunakan ClaudeSDKClient (percakapan berkelanjutan)

Terbaik untuk:
  • Melanjutkan percakapan - Ketika Anda memerlukan Claude untuk mengingat konteks
  • Pertanyaan lanjutan - Membangun berdasarkan respons sebelumnya
  • Aplikasi interaktif - Antarmuka obrolan, REPL
  • Logika berbasis respons - Ketika tindakan berikutnya bergantung pada respons Claude
  • Kontrol sesi - Mengelola siklus hidup percakapan secara eksplisit

Fungsi

query()

Membuat sesi baru untuk setiap interaksi dengan Claude Code secara default. Mengembalikan async iterator yang menghasilkan pesan saat tiba. Setiap panggilan ke query() dimulai segar tanpa memori interaksi sebelumnya kecuali Anda melewatkan continue_conversation=True atau resume dalam ClaudeAgentOptions. Lihat Sessions.
async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: ClaudeAgentOptions | None = None,
    transport: Transport | None = None
) -> AsyncIterator[Message]

Parameter

ParameterTipeDeskripsi
promptstr | AsyncIterable[dict]Prompt input sebagai string atau async iterable untuk mode streaming
optionsClaudeAgentOptions | NoneObjek konfigurasi opsional (default ke ClaudeAgentOptions() jika None)
transportTransport | NoneTransport kustom opsional untuk berkomunikasi dengan proses CLI

Pengembalian

Mengembalikan AsyncIterator[Message] yang menghasilkan pesan dari percakapan.

Contoh - Dengan opsi

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions


async def main():
    options = ClaudeAgentOptions(
        system_prompt="You are an expert Python developer",
        permission_mode="acceptEdits",
        cwd="/home/user/project",
    )

    async for message in query(prompt="Create a Python web server", options=options):
        print(message)


asyncio.run(main())

tool()

Dekorator untuk mendefinisikan tools MCP dengan keamanan tipe.
def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any],
    annotations: ToolAnnotations | None = None
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]

Parameter

ParameterTipeDeskripsi
namestrPengenal unik untuk tool
descriptionstrDeskripsi yang dapat dibaca manusia tentang apa yang dilakukan tool
input_schematype | dict[str, Any]Skema yang mendefinisikan parameter input tool (lihat di bawah)
annotationsToolAnnotations | NoneAnotasi tool MCP opsional yang memberikan petunjuk perilaku kepada klien

Opsi skema input

  1. Pemetaan tipe sederhana (direkomendasikan):
    {"text": str, "count": int, "enabled": bool}
    
  2. Format JSON Schema (untuk validasi kompleks):
    {
        "type": "object",
        "properties": {
            "text": {"type": "string"},
            "count": {"type": "integer", "minimum": 0},
        },
        "required": ["text"],
    }
    

Pengembalian

Fungsi dekorator yang membungkus implementasi tool dan mengembalikan instance SdkMcpTool.

Contoh

from claude_agent_sdk import tool
from typing import Any


@tool("greet", "Greet a user", {"name": str})
async def greet(args: dict[str, Any]) -> dict[str, Any]:
    return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}

ToolAnnotations

Diimpor ulang dari mcp.types (juga tersedia sebagai from claude_agent_sdk import ToolAnnotations). Semua field adalah petunjuk opsional; klien tidak boleh mengandalkannya untuk keputusan keamanan.
FieldTipeDefaultDeskripsi
titlestr | NoneNoneJudul yang dapat dibaca manusia untuk tool
readOnlyHintbool | NoneFalseJika True, tool tidak memodifikasi lingkungannya
destructiveHintbool | NoneTrueJika True, tool dapat melakukan pembaruan destruktif (hanya bermakna ketika readOnlyHint adalah False)
idempotentHintbool | NoneFalseJika True, panggilan berulang dengan argumen yang sama tidak memiliki efek tambahan (hanya bermakna ketika readOnlyHint adalah False)
openWorldHintbool | NoneTrueJika True, tool berinteraksi dengan entitas eksternal (misalnya, pencarian web). Jika False, domain tool ditutup (misalnya, tool memori)
from claude_agent_sdk import tool, ToolAnnotations
from typing import Any


@tool(
    "search",
    "Search the web",
    {"query": str},
    annotations=ToolAnnotations(readOnlyHint=True, openWorldHint=True),
)
async def search(args: dict[str, Any]) -> dict[str, Any]:
    return {"content": [{"type": "text", "text": f"Results for: {args['query']}"}]}

create_sdk_mcp_server()

Buat server MCP dalam proses yang berjalan dalam aplikasi Python Anda.
def create_sdk_mcp_server(
    name: str,
    version: str = "1.0.0",
    tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig

Parameter

ParameterTipeDefaultDeskripsi
namestr-Pengenal unik untuk server
versionstr"1.0.0"String versi server
toolslist[SdkMcpTool[Any]] | NoneNoneDaftar fungsi tool yang dibuat dengan dekorator @tool

Pengembalian

Mengembalikan objek McpSdkServerConfig yang dapat diteruskan ke ClaudeAgentOptions.mcp_servers.

Contoh

from claude_agent_sdk import tool, create_sdk_mcp_server


@tool("add", "Add two numbers", {"a": float, "b": float})
async def add(args):
    return {"content": [{"type": "text", "text": f"Sum: {args['a'] + args['b']}"}]}


@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
async def multiply(args):
    return {"content": [{"type": "text", "text": f"Product: {args['a'] * args['b']}"}]}


calculator = create_sdk_mcp_server(
    name="calculator",
    version="2.0.0",
    tools=[add, multiply],  # Pass decorated functions
)

# Use with Claude
options = ClaudeAgentOptions(
    mcp_servers={"calc": calculator},
    allowed_tools=["mcp__calc__add", "mcp__calc__multiply"],
)

list_sessions()

Mencantumkan sesi masa lalu dengan metadata. Filter berdasarkan direktori proyek atau cantumkan sesi di semua proyek. Sinkron; mengembalikan segera.
def list_sessions(
    directory: str | None = None,
    limit: int | None = None,
    include_worktrees: bool = True
) -> list[SDKSessionInfo]

Parameter

ParameterTipeDefaultDeskripsi
directorystr | NoneNoneDirektori untuk mencantumkan sesi. Ketika dihilangkan, mengembalikan sesi di semua proyek
limitint | NoneNoneJumlah maksimal sesi yang akan dikembalikan
include_worktreesboolTrueKetika directory berada di dalam repositori git, sertakan sesi dari semua jalur worktree

Tipe pengembalian: SDKSessionInfo

PropertiTipeDeskripsi
session_idstrPengenal sesi unik
summarystrJudul tampilan: judul kustom, ringkasan yang dihasilkan otomatis, atau prompt pertama
last_modifiedintWaktu modifikasi terakhir dalam milidetik sejak epoch
file_sizeint | NoneUkuran file sesi dalam byte (None untuk backend penyimpanan jarak jauh)
custom_titlestr | NoneJudul sesi yang ditetapkan pengguna
first_promptstr | NonePrompt pengguna bermakna pertama dalam sesi
git_branchstr | NoneCabang Git di akhir sesi
cwdstr | NoneDirektori kerja untuk sesi
tagstr | NoneTag sesi yang ditetapkan pengguna (lihat tag_session())
created_atint | NoneWaktu pembuatan sesi dalam milidetik sejak epoch

Contoh

Cetak 10 sesi terbaru untuk proyek. Hasil diurutkan berdasarkan last_modified menurun, jadi item pertama adalah yang terbaru. Hilangkan directory untuk mencari di semua proyek.
from claude_agent_sdk import list_sessions

for session in list_sessions(directory="/path/to/project", limit=10):
    print(f"{session.summary} ({session.session_id})")

get_session_messages()

Mengambil pesan dari sesi masa lalu. Sinkron; mengembalikan segera.
def get_session_messages(
    session_id: str,
    directory: str | None = None,
    limit: int | None = None,
    offset: int = 0
) -> list[SessionMessage]

Parameter

ParameterTipeDefaultDeskripsi
session_idstrdiperlukanID sesi untuk mengambil pesan
directorystr | NoneNoneDirektori proyek untuk dilihat. Ketika dihilangkan, mencari di semua proyek
limitint | NoneNoneJumlah maksimal pesan yang akan dikembalikan
offsetint0Jumlah pesan yang akan dilewati dari awal

Tipe pengembalian: SessionMessage

PropertiTipeDeskripsi
typeLiteral["user", "assistant"]Peran pesan
uuidstrPengenal pesan unik
session_idstrPengenal sesi
messageAnyKonten pesan mentah
parent_tool_use_idNoneDicadangkan untuk penggunaan di masa depan

Contoh

from claude_agent_sdk import list_sessions, get_session_messages

sessions = list_sessions(limit=1)
if sessions:
    messages = get_session_messages(sessions[0].session_id)
    for msg in messages:
        print(f"[{msg.type}] {msg.uuid}")

get_session_info()

Membaca metadata untuk sesi tunggal berdasarkan ID tanpa memindai direktori proyek lengkap. Sinkron; mengembalikan segera.
def get_session_info(
    session_id: str,
    directory: str | None = None,
) -> SDKSessionInfo | None

Parameter

ParameterTipeDefaultDeskripsi
session_idstrdiperlukanUUID sesi untuk dicari
directorystr | NoneNoneJalur direktori proyek. Ketika dihilangkan, mencari di semua direktori proyek
Mengembalikan SDKSessionInfo, atau None jika sesi tidak ditemukan.

Contoh

Cari metadata sesi tunggal tanpa memindai direktori proyek. Berguna ketika Anda sudah memiliki ID sesi dari run sebelumnya.
from claude_agent_sdk import get_session_info

info = get_session_info("550e8400-e29b-41d4-a716-446655440000")
if info:
    print(f"{info.summary} (branch: {info.git_branch}, tag: {info.tag})")

rename_session()

Mengganti nama sesi dengan menambahkan entri judul kustom. Panggilan berulang aman; judul terbaru menang. Sinkron.
def rename_session(
    session_id: str,
    title: str,
    directory: str | None = None,
) -> None

Parameter

ParameterTipeDefaultDeskripsi
session_idstrdiperlukanUUID sesi untuk diganti nama
titlestrdiperlukanJudul baru. Harus tidak kosong setelah menghapus spasi putih
directorystr | NoneNoneJalur direktori proyek. Ketika dihilangkan, mencari di semua direktori proyek
Menimbulkan ValueError jika session_id bukan UUID yang valid atau title kosong; FileNotFoundError jika sesi tidak dapat ditemukan.

Contoh

Ganti nama sesi terbaru sehingga lebih mudah ditemukan nanti. Judul baru muncul di SDKSessionInfo.custom_title pada pembacaan berikutnya.
from claude_agent_sdk import list_sessions, rename_session

sessions = list_sessions(directory="/path/to/project", limit=1)
if sessions:
    rename_session(sessions[0].session_id, "Refactor auth module")

tag_session()

Menandai sesi. Teruskan None untuk menghapus tag. Panggilan berulang aman; tag terbaru menang. Sinkron.
def tag_session(
    session_id: str,
    tag: str | None,
    directory: str | None = None,
) -> None

Parameter

ParameterTipeDefaultDeskripsi
session_idstrdiperlukanUUID sesi untuk ditandai
tagstr | NonediperlukanString tag, atau None untuk menghapus. Disanitasi Unicode sebelum disimpan
directorystr | NoneNoneJalur direktori proyek. Ketika dihilangkan, mencari di semua direktori proyek
Menimbulkan ValueError jika session_id bukan UUID yang valid atau tag kosong setelah sanitasi; FileNotFoundError jika sesi tidak dapat ditemukan.

Contoh

Tandai sesi, kemudian filter berdasarkan tag itu pada pembacaan nanti. Teruskan None untuk menghapus tag yang ada.
from claude_agent_sdk import list_sessions, tag_session

# Tag a session
tag_session("550e8400-e29b-41d4-a716-446655440000", "needs-review")

# Later: find all sessions with that tag
for session in list_sessions(directory="/path/to/project"):
    if session.tag == "needs-review":
        print(session.summary)

Kelas

ClaudeSDKClient

Mempertahankan sesi percakapan di beberapa pertukaran. Ini adalah setara Python dari cara fungsi query() SDK TypeScript bekerja secara internal - ia membuat objek klien yang dapat melanjutkan percakapan.

Fitur Utama

  • Kontinuitas sesi: Mempertahankan konteks percakapan di beberapa panggilan query()
  • Percakapan yang sama: Sesi mempertahankan pesan sebelumnya
  • Dukungan interrupt: Dapat menghentikan eksekusi di tengah-tengah tugas
  • Siklus hidup eksplisit: Anda mengontrol kapan sesi dimulai dan berakhir
  • Alur berbasis respons: Dapat bereaksi terhadap respons dan mengirim tindak lanjut
  • Tools dan hooks kustom: Mendukung tools kustom (dibuat dengan dekorator @tool) dan hooks
class ClaudeSDKClient:
    def __init__(self, options: ClaudeAgentOptions | None = None, transport: Transport | None = None)
    async def connect(self, prompt: str | AsyncIterable[dict] | None = None) -> None
    async def query(self, prompt: str | AsyncIterable[dict], session_id: str = "default") -> None
    async def receive_messages(self) -> AsyncIterator[Message]
    async def receive_response(self) -> AsyncIterator[Message]
    async def interrupt(self) -> None
    async def set_permission_mode(self, mode: str) -> None
    async def set_model(self, model: str | None = None) -> None
    async def rewind_files(self, user_message_id: str) -> None
    async def get_mcp_status(self) -> McpStatusResponse
    async def reconnect_mcp_server(self, server_name: str) -> None
    async def toggle_mcp_server(self, server_name: str, enabled: bool) -> None
    async def stop_task(self, task_id: str) -> None
    async def get_server_info(self) -> dict[str, Any] | None
    async def disconnect(self) -> None

Metode

MetodeDeskripsi
__init__(options)Inisialisasi klien dengan konfigurasi opsional
connect(prompt)Hubungkan ke Claude dengan prompt awal opsional atau aliran pesan
query(prompt, session_id)Kirim permintaan baru dalam mode streaming
receive_messages()Terima semua pesan dari Claude sebagai async iterator
receive_response()Terima pesan hingga dan termasuk ResultMessage
interrupt()Kirim sinyal interrupt (hanya bekerja dalam mode streaming)
set_permission_mode(mode)Ubah mode izin untuk sesi saat ini
set_model(model)Ubah model untuk sesi saat ini. Teruskan None untuk reset ke default
rewind_files(user_message_id)Pulihkan file ke keadaan mereka pada pesan pengguna yang ditentukan. Memerlukan enable_file_checkpointing=True. Lihat File checkpointing
get_mcp_status()Dapatkan status semua server MCP yang dikonfigurasi. Mengembalikan McpStatusResponse
reconnect_mcp_server(server_name)Coba lagi menghubungkan ke server MCP yang gagal atau terputus
toggle_mcp_server(server_name, enabled)Aktifkan atau nonaktifkan server MCP di tengah sesi. Menonaktifkan menghapus toolnya
stop_task(task_id)Hentikan tugas latar belakang yang sedang berjalan. TaskNotificationMessage dengan status "stopped" mengikuti dalam aliran pesan
get_server_info()Dapatkan informasi server termasuk ID sesi dan kemampuan
disconnect()Putuskan sambungan dari Claude

Dukungan Context Manager

Klien dapat digunakan sebagai async context manager untuk manajemen koneksi otomatis:
async with ClaudeSDKClient() as client:
    await client.query("Hello Claude")
    async for message in client.receive_response():
        print(message)
Penting: Saat mengulangi pesan, hindari menggunakan break untuk keluar lebih awal karena ini dapat menyebabkan masalah pembersihan asyncio. Sebaliknya, biarkan iterasi selesai secara alami atau gunakan flag untuk melacak kapan Anda menemukan apa yang Anda butuhkan.

Contoh - Melanjutkan percakapan

import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage


async def main():
    async with ClaudeSDKClient() as client:
        # First question
        await client.query("What's the capital of France?")

        # Process response
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude: {block.text}")

        # Follow-up question - the session retains the previous context
        await client.query("What's the population of that city?")

        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude: {block.text}")

        # Another follow-up - still in the same conversation
        await client.query("What are some famous landmarks there?")

        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude: {block.text}")


asyncio.run(main())

Contoh - Streaming input dengan ClaudeSDKClient

import asyncio
from claude_agent_sdk import ClaudeSDKClient


async def message_stream():
    """Generate messages dynamically."""
    yield {
        "type": "user",
        "message": {"role": "user", "content": "Analyze the following data:"},
    }
    await asyncio.sleep(0.5)
    yield {
        "type": "user",
        "message": {"role": "user", "content": "Temperature: 25°C, Humidity: 60%"},
    }
    await asyncio.sleep(0.5)
    yield {
        "type": "user",
        "message": {"role": "user", "content": "What patterns do you see?"},
    }


async def main():
    async with ClaudeSDKClient() as client:
        # Stream input to Claude
        await client.query(message_stream())

        # Process response
        async for message in client.receive_response():
            print(message)

        # Follow-up in same session
        await client.query("Should we be concerned about these readings?")

        async for message in client.receive_response():
            print(message)


asyncio.run(main())

Contoh - Menggunakan interrupts

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, ResultMessage


async def interruptible_task():
    options = ClaudeAgentOptions(allowed_tools=["Bash"], permission_mode="acceptEdits")

    async with ClaudeSDKClient(options=options) as client:
        # Start a long-running task
        await client.query("Count from 1 to 100 slowly, using the bash sleep command")

        # Let it run for a bit
        await asyncio.sleep(2)

        # Interrupt the task
        await client.interrupt()
        print("Task interrupted!")

        # Drain the interrupted task's messages (including its ResultMessage)
        async for message in client.receive_response():
            if isinstance(message, ResultMessage):
                print(f"Interrupted task finished with subtype={message.subtype!r}")
                # subtype is "error_during_execution" for interrupted tasks

        # Send a new command
        await client.query("Just say hello instead")

        # Now receive the new response
        async for message in client.receive_response():
            if isinstance(message, ResultMessage) and message.subtype == "success":
                print(f"New result: {message.result}")


asyncio.run(interruptible_task())
Perilaku buffer setelah interrupt: interrupt() mengirim sinyal berhenti tetapi tidak menghapus buffer pesan. Pesan yang sudah diproduksi oleh tugas yang terputus, termasuk ResultMessage-nya (dengan subtype="error_during_execution"), tetap berada dalam aliran. Anda harus menguras mereka dengan receive_response() sebelum membaca respons ke query baru. Jika Anda mengirim query baru segera setelah interrupt() dan memanggil receive_response() hanya sekali, Anda akan menerima pesan tugas yang terputus, bukan respons query baru.

Contoh - Kontrol izin lanjutan

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import (
    PermissionResultAllow,
    PermissionResultDeny,
    ToolPermissionContext,
)


async def custom_permission_handler(
    tool_name: str, input_data: dict, context: ToolPermissionContext
) -> PermissionResultAllow | PermissionResultDeny:
    """Custom logic for tool permissions."""

    # Block writes to system directories
    if tool_name == "Write" and input_data.get("file_path", "").startswith("/system/"):
        return PermissionResultDeny(
            message="System directory write not allowed", interrupt=True
        )

    # Redirect sensitive file operations
    if tool_name in ["Write", "Edit"] and "config" in input_data.get("file_path", ""):
        safe_path = f"./sandbox/{input_data['file_path']}"
        return PermissionResultAllow(
            updated_input={**input_data, "file_path": safe_path}
        )

    # Allow everything else
    return PermissionResultAllow(updated_input=input_data)


async def main():
    options = ClaudeAgentOptions(
        can_use_tool=custom_permission_handler, allowed_tools=["Read", "Write", "Edit"]
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Update the system config file")

        async for message in client.receive_response():
            # Will use sandbox path instead
            print(message)


asyncio.run(main())

Tipe

@dataclass vs TypedDict: SDK ini menggunakan dua jenis tipe. Kelas yang didekorasi dengan @dataclass (seperti ResultMessage, AgentDefinition, TextBlock) adalah instance objek saat runtime dan mendukung akses atribut: msg.result. Kelas yang didefinisikan dengan TypedDict (seperti ThinkingConfigEnabled, McpStdioServerConfig, SyncHookJSONOutput) adalah dict biasa saat runtime dan memerlukan akses kunci: config["budget_tokens"], bukan config.budget_tokens. Sintaks panggilan ClassName(field=value) bekerja untuk keduanya, tetapi hanya dataclass yang menghasilkan objek dengan atribut.

SdkMcpTool

Definisi untuk tool SDK MCP yang dibuat dengan dekorator @tool.
@dataclass
class SdkMcpTool(Generic[T]):
    name: str
    description: str
    input_schema: type[T] | dict[str, Any]
    handler: Callable[[T], Awaitable[dict[str, Any]]]
    annotations: ToolAnnotations | None = None
PropertiTipeDeskripsi
namestrPengenal unik untuk tool
descriptionstrDeskripsi yang dapat dibaca manusia
input_schematype[T] | dict[str, Any]Skema untuk validasi input
handlerCallable[[T], Awaitable[dict[str, Any]]]Fungsi async yang menangani eksekusi tool
annotationsToolAnnotations | NoneAnotasi tool MCP opsional (misalnya, readOnlyHint, destructiveHint, openWorldHint). Dari mcp.types

Transport

Kelas dasar abstrak untuk implementasi transport kustom. Gunakan ini untuk berkomunikasi dengan proses Claude melalui saluran kustom (misalnya, koneksi jarak jauh alih-alih subprocess lokal).
Ini adalah API internal tingkat rendah. Antarmuka dapat berubah di rilis mendatang. Implementasi kustom harus diperbarui agar sesuai dengan perubahan antarmuka apa pun.
from abc import ABC, abstractmethod
from collections.abc import AsyncIterator
from typing import Any


class Transport(ABC):
    @abstractmethod
    async def connect(self) -> None: ...

    @abstractmethod
    async def write(self, data: str) -> None: ...

    @abstractmethod
    def read_messages(self) -> AsyncIterator[dict[str, Any]]: ...

    @abstractmethod
    async def close(self) -> None: ...

    @abstractmethod
    def is_ready(self) -> bool: ...

    @abstractmethod
    async def end_input(self) -> None: ...
MetodeDeskripsi
connect()Hubungkan transport dan siapkan untuk komunikasi
write(data)Tulis data mentah (JSON + newline) ke transport
read_messages()Async iterator yang menghasilkan pesan JSON yang diuraikan
close()Tutup koneksi dan bersihkan sumber daya
is_ready()Mengembalikan True jika transport dapat mengirim dan menerima
end_input()Tutup aliran input (misalnya, tutup stdin untuk transport subprocess)
Impor: from claude_agent_sdk import Transport

ClaudeAgentOptions

Dataclass konfigurasi untuk query Claude Code.
@dataclass
class ClaudeAgentOptions:
    tools: list[str] | ToolsPreset | None = None
    allowed_tools: list[str] = field(default_factory=list)
    system_prompt: str | SystemPromptPreset | None = None
    mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
    strict_mcp_config: bool = False
    permission_mode: PermissionMode | None = None
    continue_conversation: bool = False
    resume: str | None = None
    max_turns: int | None = None
    max_budget_usd: float | None = None
    disallowed_tools: list[str] = field(default_factory=list)
    model: str | None = None
    fallback_model: str | None = None
    betas: list[SdkBeta] = field(default_factory=list)
    output_format: dict[str, Any] | None = None
    permission_prompt_tool_name: str | None = None
    cwd: str | Path | None = None
    cli_path: str | Path | None = None
    settings: str | None = None
    add_dirs: list[str | Path] = field(default_factory=list)
    env: dict[str, str] = field(default_factory=dict)
    extra_args: dict[str, str | None] = field(default_factory=dict)
    max_buffer_size: int | None = None
    debug_stderr: Any = sys.stderr  # Deprecated
    stderr: Callable[[str], None] | None = None
    can_use_tool: CanUseTool | None = None
    hooks: dict[HookEvent, list[HookMatcher]] | None = None
    user: str | None = None
    include_partial_messages: bool = False
    include_hook_events: bool = False
    fork_session: bool = False
    agents: dict[str, AgentDefinition] | None = None
    setting_sources: list[SettingSource] | None = None
    sandbox: SandboxSettings | None = None
    plugins: list[SdkPluginConfig] = field(default_factory=list)
    max_thinking_tokens: int | None = None  # Deprecated: use thinking instead
    thinking: ThinkingConfig | None = None
    effort: EffortLevel | None = None
    enable_file_checkpointing: bool = False
    session_store: SessionStore | None = None
    session_store_flush: SessionStoreFlushMode = "batched"
PropertiTipeDefaultDeskripsi
toolslist[str] | ToolsPreset | NoneNoneKonfigurasi tools. Gunakan {"type": "preset", "preset": "claude_code"} untuk tools default Claude Code
allowed_toolslist[str][]Tools untuk auto-approve tanpa prompt. Ini tidak membatasi Claude hanya pada tools ini; tools yang tidak terdaftar jatuh ke permission_mode dan can_use_tool. Gunakan disallowed_tools untuk memblokir tools. Lihat Permissions
system_promptstr | SystemPromptPreset | NoneNoneKonfigurasi system prompt. Teruskan string untuk prompt kustom, atau gunakan {"type": "preset", "preset": "claude_code"} untuk system prompt Claude Code. Tambahkan "append" untuk memperluas preset
mcp_serversdict[str, McpServerConfig] | str | Path{}Konfigurasi server MCP atau jalur ke file konfigurasi
strict_mcp_configboolFalseKetika True, gunakan hanya server yang diteruskan dalam mcp_servers dan abaikan .mcp.json proyek, pengaturan pengguna, server MCP yang disediakan plugin, dan konektor claude.ai. Memetakan ke flag CLI --strict-mcp-config
permission_modePermissionMode | NoneNoneMode izin untuk penggunaan tool
continue_conversationboolFalseLanjutkan percakapan terbaru
resumestr | NoneNoneID sesi untuk dilanjutkan
max_turnsint | NoneNoneJumlah maksimal putaran agentic (round trip penggunaan tool)
max_budget_usdfloat | NoneNoneHentikan query ketika estimasi biaya sisi klien mencapai nilai USD ini. Dibandingkan dengan estimasi yang sama seperti total_cost_usd; lihat Track cost and usage untuk peringatan akurasi
disallowed_toolslist[str][]Tools untuk ditolak. Nama bare seperti "Bash" menghapus tool dari konteks Claude. Aturan scoped seperti "Bash(rm *)" membiarkan tool tersedia dan menolak panggilan yang cocok di setiap mode izin, termasuk bypassPermissions. Lihat Permissions
enable_file_checkpointingboolFalseAktifkan pelacakan perubahan file untuk rewinding. Lihat File checkpointing
modelstr | NoneNoneModel Claude yang akan digunakan
fallback_modelstr | NoneNoneModel fallback yang akan digunakan jika model utama gagal
betaslist[SdkBeta][]Fitur beta untuk diaktifkan. Lihat SdkBeta untuk opsi yang tersedia
output_formatdict[str, Any] | NoneNoneFormat output untuk respons terstruktur (misalnya, {"type": "json_schema", "schema": {...}}). Lihat Structured outputs untuk detail
permission_prompt_tool_namestr | NoneNoneNama tool MCP untuk prompt izin
cwdstr | Path | NoneNoneDirektori kerja saat ini
cli_pathstr | Path | NoneNoneJalur kustom ke executable CLI Claude Code
settingsstr | NoneNoneJalur ke file pengaturan
add_dirslist[str | Path][]Direktori tambahan yang dapat diakses Claude
envdict[str, str]{}Variabel lingkungan yang digabungkan di atas lingkungan proses yang diwarisi. Lihat Environment variables untuk variabel yang dibaca CLI yang mendasar, dan Handle slow or stalled API responses untuk variabel terkait timeout
extra_argsdict[str, str | None]{}Argumen CLI tambahan untuk diteruskan langsung ke CLI
max_buffer_sizeint | NoneNoneByte maksimal saat membuffer stdout CLI
debug_stderrAnysys.stderrDeprecated - Objek seperti file untuk output debug. Gunakan callback stderr sebagai gantinya
stderrCallable[[str], None] | NoneNoneFungsi callback untuk output stderr dari CLI
can_use_toolCanUseTool | NoneNoneFungsi callback izin tool. Lihat Permission types untuk detail
hooksdict[HookEvent, list[HookMatcher]] | NoneNoneKonfigurasi hook untuk mengintersepsi event
userstr | NoneNonePengenal pengguna
include_partial_messagesboolFalseSertakan event streaming pesan parsial. Ketika diaktifkan, pesan StreamEvent dihasilkan
include_hook_eventsboolFalseSertakan event lifecycle hook dalam aliran pesan sebagai objek HookEventMessage
fork_sessionboolFalseKetika melanjutkan dengan resume, fork ke ID sesi baru alih-alih melanjutkan sesi asli
agentsdict[str, AgentDefinition] | NoneNoneSubagent yang didefinisikan secara programatis
pluginslist[SdkPluginConfig][]Muat plugin kustom dari jalur lokal. Lihat Plugins untuk detail
sandboxSandboxSettings | NoneNoneKonfigurasi perilaku sandbox secara programatis. Lihat Sandbox settings untuk detail
setting_sourceslist[SettingSource] | NoneNone (CLI defaults: all sources)Kontrol pengaturan filesystem mana yang akan dimuat. Teruskan [] untuk menonaktifkan pengaturan pengguna, proyek, dan lokal. Pengaturan kebijakan terkelola dimuat terlepas dari itu. Lihat Use Claude Code features
skillslist[str] | Literal["all"] | NoneNoneSkills yang tersedia untuk sesi. Teruskan "all" untuk mengaktifkan setiap skill yang ditemukan, atau daftar nama skill. Ketika diatur, SDK secara otomatis menambahkan tool Skill ke allowed_tools. Jika Anda juga meneruskan tools, sertakan "Skill" dalam daftar itu. Lihat Skills
max_thinking_tokensint | NoneNoneDeprecated - Token maksimal untuk blok thinking. Gunakan thinking sebagai gantinya
thinkingThinkingConfig | NoneNoneMengontrol perilaku extended thinking. Mengambil prioritas atas max_thinking_tokens
effortEffortLevel | NoneNoneTingkat usaha untuk kedalaman thinking
session_storeSessionStore | NoneNoneCerminkan transkrip sesi ke backend eksternal sehingga host apa pun dapat melanjutkannya. Lihat Persist sessions to external storage
session_store_flushLiteral["batched", "eager"]"batched"Kapan membuang entri transkrip yang dicerminkan ke session_store. "batched" membuang sekali per putaran atau ketika buffer penuh; "eager" memicu pembilasan latar belakang setelah setiap frame. Diabaikan ketika session_store adalah None

Menangani respons API yang lambat atau terhenti

Subprocess CLI membaca beberapa variabel lingkungan yang mengontrol timeout API dan deteksi stall. Teruskan melalui ClaudeAgentOptions.env:
options = ClaudeAgentOptions(
    env={
        "API_TIMEOUT_MS": "120000",
        "CLAUDE_CODE_MAX_RETRIES": "2",
        "CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS": "120000",
    },
)
  • API_TIMEOUT_MS: timeout per-permintaan pada klien Anthropic, dalam milidetik. Default 600000. Berlaku untuk loop utama dan semua subagent.
  • CLAUDE_CODE_MAX_RETRIES: maksimal retry API. Default 10. Setiap retry mendapat jendela API_TIMEOUT_MS sendiri, jadi waktu dinding terburuk kira-kira API_TIMEOUT_MS × (CLAUDE_CODE_MAX_RETRIES + 1) ditambah backoff.
  • CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS: watchdog stall untuk subagent yang diluncurkan dengan run_in_background. Default 600000. Direset pada setiap event stream; pada stall itu membatalkan subagent, menandai tugas gagal, dan menampilkan error ke parent dengan hasil parsial apa pun. Tidak berlaku untuk subagent sinkron.
  • CLAUDE_ENABLE_STREAM_WATCHDOG=1 dengan CLAUDE_STREAM_IDLE_TIMEOUT_MS: membatalkan permintaan ketika header telah tiba tetapi badan respons berhenti streaming. Dimatikan secara default. CLAUDE_STREAM_IDLE_TIMEOUT_MS default ke 300000 dan diklem ke minimum itu. Permintaan yang dibatalkan melalui jalur retry normal.

OutputFormat

Konfigurasi untuk validasi output terstruktur. Teruskan ini sebagai dict ke field output_format pada ClaudeAgentOptions:
# Expected dict shape for output_format
{
    "type": "json_schema",
    "schema": {...},  # Your JSON Schema definition
}
FieldDiperlukanDeskripsi
typeYaHarus "json_schema" untuk validasi JSON Schema
schemaYaDefinisi JSON Schema untuk validasi output

SystemPromptPreset

Konfigurasi untuk menggunakan preset system prompt Claude Code dengan penambahan opsional.
class SystemPromptPreset(TypedDict):
    type: Literal["preset"]
    preset: Literal["claude_code"]
    append: NotRequired[str]
    exclude_dynamic_sections: NotRequired[bool]
FieldDiperlukanDeskripsi
typeYaHarus "preset" untuk menggunakan preset system prompt
presetYaHarus "claude_code" untuk menggunakan system prompt Claude Code
appendTidakInstruksi tambahan untuk ditambahkan ke preset system prompt
exclude_dynamic_sectionsTidakPindahkan konteks per-sesi seperti direktori kerja, status git-repo, dan jalur memori otomatis dari system prompt ke pesan pengguna pertama. Meningkatkan reuse prompt-cache di seluruh pengguna dan mesin. Lihat Modify system prompts

SettingSource

Mengontrol sumber konfigurasi berbasis filesystem mana yang dimuat pengaturan SDK.
SettingSource = Literal["user", "project", "local"]
NilaiDeskripsiLokasi
"user"Pengaturan pengguna global~/.claude/settings.json
"project"Pengaturan proyek bersama (version controlled).claude/settings.json
"local"Pengaturan proyek lokal (gitignored).claude/settings.local.json

Perilaku default

Ketika setting_sources dihilangkan atau None, query() memuat pengaturan filesystem yang sama seperti CLI Claude Code: pengguna, proyek, dan lokal. Pengaturan kebijakan terkelola dimuat dalam semua kasus. Lihat What settingSources does not control untuk input yang dibaca terlepas dari opsi ini, dan cara menonaktifkannya.

Mengapa menggunakan setting_sources

Nonaktifkan pengaturan filesystem:
# Do not load user, project, or local settings from disk
from claude_agent_sdk import query, ClaudeAgentOptions

async for message in query(
    prompt="Analyze this code",
    options=ClaudeAgentOptions(
        setting_sources=[]
    ),
):
    print(message)
Dalam Python SDK 0.1.59 dan lebih awal, daftar kosong diperlakukan sama dengan menghilangkan opsi, jadi setting_sources=[] tidak menonaktifkan pengaturan filesystem. Upgrade ke rilis yang lebih baru jika Anda memerlukan daftar kosong untuk berlaku. SDK TypeScript tidak terpengaruh.
Muat semua pengaturan filesystem secara eksplisit:
from claude_agent_sdk import query, ClaudeAgentOptions

async for message in query(
    prompt="Analyze this code",
    options=ClaudeAgentOptions(
        setting_sources=["user", "project", "local"]
    ),
):
    print(message)
Muat hanya sumber pengaturan tertentu:
# Load only project settings, ignore user and local
async for message in query(
    prompt="Run CI checks",
    options=ClaudeAgentOptions(
        setting_sources=["project"]  # Only .claude/settings.json
    ),
):
    print(message)
Lingkungan testing dan CI:
# Ensure consistent behavior in CI by excluding local settings
async for message in query(
    prompt="Run tests",
    options=ClaudeAgentOptions(
        setting_sources=["project"],  # Only team-shared settings
        permission_mode="bypassPermissions",
    ),
):
    print(message)
Aplikasi SDK-only:
# Define everything programmatically.
# Pass [] to opt out of filesystem setting sources.
async for message in query(
    prompt="Review this PR",
    options=ClaudeAgentOptions(
        setting_sources=[],
        agents={...},
        mcp_servers={...},
        allowed_tools=["Read", "Grep", "Glob"],
    ),
):
    print(message)
Memuat instruksi proyek CLAUDE.md:
# Load project settings to include CLAUDE.md files
async for message in query(
    prompt="Add a new feature following project conventions",
    options=ClaudeAgentOptions(
        system_prompt={
            "type": "preset",
            "preset": "claude_code",  # Use Claude Code's system prompt
        },
        setting_sources=["project"],  # Loads CLAUDE.md from project
        allowed_tools=["Read", "Write", "Edit"],
    ),
):
    print(message)

Preseden pengaturan

Ketika beberapa sumber dimuat, pengaturan digabungkan dengan preseden ini (tertinggi ke terendah):
  1. Pengaturan lokal (.claude/settings.local.json)
  2. Pengaturan proyek (.claude/settings.json)
  3. Pengaturan pengguna (~/.claude/settings.json)
Opsi programatis seperti agents dan allowed_tools mengganti pengaturan filesystem pengguna, proyek, dan lokal. Pengaturan kebijakan terkelola mengambil prioritas atas opsi programatis.

AgentDefinition

Konfigurasi untuk subagent yang didefinisikan secara programatis.
@dataclass
class AgentDefinition:
    description: str
    prompt: str
    tools: list[str] | None = None
    disallowedTools: list[str] | None = None
    model: str | None = None
    skills: list[str] | None = None
    memory: Literal["user", "project", "local"] | None = None
    mcpServers: list[str | dict[str, Any]] | None = None
    initialPrompt: str | None = None
    maxTurns: int | None = None
    background: bool | None = None
    effort: EffortLevel | int | None = None
    permissionMode: PermissionMode | None = None
FieldDiperlukanDeskripsi
descriptionYaDeskripsi bahasa alami tentang kapan menggunakan agent ini
promptYaSystem prompt agent
toolsTidakArray nama tool yang diizinkan. Jika dihilangkan, mewarisi semua tools
disallowedToolsTidakArray nama tool untuk dihapus dari set tool agent
modelTidakPenggantian model untuk agent ini. Menerima alias seperti "sonnet", "opus", "haiku", atau "inherit", atau ID model lengkap. Jika dihilangkan, menggunakan model utama
skillsTidakDaftar nama skill untuk preload ke dalam konteks agent saat startup. Skill yang tidak terdaftar tetap dapat dipanggil melalui tool Skill
memoryTidakSumber memori untuk agent ini: "user", "project", atau "local"
mcpServersTidakServer MCP yang tersedia untuk agent ini. Setiap entri adalah nama server atau dict {name: config} inline
initialPromptTidakAuto-submitted sebagai putaran pengguna pertama ketika agent ini berjalan sebagai agent thread utama
maxTurnsTidakJumlah maksimal putaran agentic sebelum agent berhenti
backgroundTidakJalankan agent ini sebagai tugas latar belakang non-blocking ketika dipanggil
effortTidakTingkat usaha reasoning untuk agent ini. Menerima tingkat bernama atau integer. Lihat EffortLevel
permissionModeTidakMode izin untuk eksekusi tool dalam agent ini. Lihat PermissionMode
Field AgentDefinition menggunakan camelCase, seperti disallowedTools, permissionMode, dan maxTurns. Nama-nama ini memetakan langsung ke format wire yang dibagikan dengan SDK TypeScript. Ini berbeda dari ClaudeAgentOptions, yang menggunakan Python snake_case untuk field tingkat atas yang setara seperti disallowed_tools dan permission_mode. Karena AgentDefinition adalah dataclass, melewatkan keyword snake_case menimbulkan TypeError pada waktu konstruksi.

PermissionMode

Mode izin untuk mengontrol eksekusi tool.
PermissionMode = Literal[
    "default",  # Standard permission behavior
    "acceptEdits",  # Auto-accept file edits
    "plan",  # Planning mode - read-only tools only
    "dontAsk",  # Deny anything not pre-approved instead of prompting
    "bypassPermissions",  # Bypass all permission checks (use with caution)
]

EffortLevel

Tingkat usaha untuk membimbing kedalaman thinking.
EffortLevel = Literal[
    "low",  # Minimal thinking, fastest responses
    "medium",  # Moderate thinking
    "high",  # Deep reasoning
    "xhigh",  # Extended reasoning (Opus 4.7 only; falls back to "high" on other models)
    "max",  # Maximum effort
]

CanUseTool

Type alias untuk fungsi callback izin tool.
CanUseTool = Callable[
    [str, dict[str, Any], ToolPermissionContext], Awaitable[PermissionResult]
]
Callback menerima:
  • tool_name: Nama tool yang sedang dipanggil
  • input_data: Parameter input tool
  • context: ToolPermissionContext dengan informasi tambahan
Mengembalikan PermissionResult (baik PermissionResultAllow atau PermissionResultDeny).

ToolPermissionContext

Informasi konteks yang diteruskan ke callback izin tool.
@dataclass
class ToolPermissionContext:
    signal: Any | None = None  # Future: abort signal support
    suggestions: list[PermissionUpdate] = field(default_factory=list)
    blocked_path: str | None = None
    decision_reason: str | None = None
    title: str | None = None
    display_name: str | None = None
    description: str | None = None
FieldTipeDeskripsi
signalAny | NoneDicadangkan untuk dukungan sinyal abort di masa depan
suggestionslist[PermissionUpdate]Saran pembaruan izin dari CLI. Prompt Bash menyertakan saran dengan destinasi localSettings, jadi mengembalikannya dalam updated_permissions menulis aturan ke .claude/settings.local.json dan bertahan di seluruh sesi.
blocked_pathstr | NoneJalur file yang memicu permintaan izin, jika berlaku. Misalnya, ketika perintah Bash mencoba mengakses jalur di luar direktori yang diizinkan
decision_reasonstr | NoneAlasan permintaan izin ini dipicu. Diteruskan dari permissionDecisionReason hook PreToolUse ketika hook mengembalikan "ask"
titlestr | NoneKalimat prompt izin lengkap, seperti Claude wants to read foo.txt. Gunakan sebagai teks prompt utama ketika ada
display_namestr | NoneFrasa kata benda pendek untuk aksi tool, seperti Read file, cocok untuk label tombol
descriptionstr | NoneSubtitle yang dapat dibaca manusia untuk UI izin

PermissionResult

Tipe union untuk hasil callback izin.
PermissionResult = PermissionResultAllow | PermissionResultDeny

PermissionResultAllow

Hasil yang menunjukkan panggilan tool harus diizinkan.
@dataclass
class PermissionResultAllow:
    behavior: Literal["allow"] = "allow"
    updated_input: dict[str, Any] | None = None
    updated_permissions: list[PermissionUpdate] | None = None
FieldTipeDefaultDeskripsi
behaviorLiteral["allow"]"allow"Harus “allow”
updated_inputdict[str, Any] | NoneNoneInput yang dimodifikasi untuk digunakan alih-alih asli
updated_permissionslist[PermissionUpdate] | NoneNonePembaruan izin untuk diterapkan

PermissionResultDeny

Hasil yang menunjukkan panggilan tool harus ditolak.
@dataclass
class PermissionResultDeny:
    behavior: Literal["deny"] = "deny"
    message: str = ""
    interrupt: bool = False
FieldTipeDefaultDeskripsi
behaviorLiteral["deny"]"deny"Harus “deny”
messagestr""Pesan yang menjelaskan mengapa tool ditolak
interruptboolFalseApakah akan mengganggu eksekusi saat ini

PermissionUpdate

Konfigurasi untuk memperbarui izin secara programatis.
@dataclass
class PermissionUpdate:
    type: Literal[
        "addRules",
        "replaceRules",
        "removeRules",
        "setMode",
        "addDirectories",
        "removeDirectories",
    ]
    rules: list[PermissionRuleValue] | None = None
    behavior: Literal["allow", "deny", "ask"] | None = None
    mode: PermissionMode | None = None
    directories: list[str] | None = None
    destination: (
        Literal["userSettings", "projectSettings", "localSettings", "session"] | None
    ) = None
FieldTipeDeskripsi
typeLiteral[...]Jenis operasi pembaruan izin
ruleslist[PermissionRuleValue] | NoneAturan untuk operasi add/replace/remove
behaviorLiteral["allow", "deny", "ask"] | NonePerilaku untuk operasi berbasis aturan
modePermissionMode | NoneMode untuk operasi setMode
directorieslist[str] | NoneDirektori untuk operasi add/remove direktori
destinationLiteral[...] | NoneDi mana menerapkan pembaruan izin

PermissionRuleValue

Aturan untuk ditambahkan, diganti, atau dihapus dalam pembaruan izin.
@dataclass
class PermissionRuleValue:
    tool_name: str
    rule_content: str | None = None

ToolsPreset

Konfigurasi preset tools untuk menggunakan set tool default Claude Code.
class ToolsPreset(TypedDict):
    type: Literal["preset"]
    preset: Literal["claude_code"]

ThinkingConfig

Mengontrol perilaku extended thinking. Union dari tiga konfigurasi:
ThinkingDisplay = Literal["summarized", "omitted"]


class ThinkingConfigAdaptive(TypedDict):
    type: Literal["adaptive"]
    display: NotRequired[ThinkingDisplay]


class ThinkingConfigEnabled(TypedDict):
    type: Literal["enabled"]
    budget_tokens: int
    display: NotRequired[ThinkingDisplay]


class ThinkingConfigDisabled(TypedDict):
    type: Literal["disabled"]


ThinkingConfig = ThinkingConfigAdaptive | ThinkingConfigEnabled | ThinkingConfigDisabled
VarianFieldDeskripsi
adaptivetype, displayClaude secara adaptif memutuskan kapan harus berpikir
enabledtype, budget_tokens, displayAktifkan thinking dengan budget token tertentu
disabledtypeNonaktifkan thinking
Field opsional display mengontrol apakah teks thinking dikembalikan "summarized" atau "omitted". Pada Claude Opus 4.7 dan lebih baru, default API adalah "omitted", jadi atur "summarized" untuk menerima konten thinking dalam output ThinkingBlock. Karena ini adalah kelas TypedDict, mereka adalah dict biasa saat runtime. Baik buatlah sebagai dict literal atau panggil kelas seperti konstruktor; keduanya menghasilkan dict. Akses field dengan config["budget_tokens"], bukan config.budget_tokens:
from claude_agent_sdk import ClaudeAgentOptions, ThinkingConfigEnabled

# Option 1: dict literal (recommended, no import needed)
options = ClaudeAgentOptions(thinking={"type": "enabled", "budget_tokens": 20000})

# Option 2: constructor-style (returns a plain dict)
config = ThinkingConfigEnabled(type="enabled", budget_tokens=20000)
print(config["budget_tokens"])  # 20000
# config.budget_tokens would raise AttributeError

SdkBeta

Tipe literal untuk fitur beta SDK.
SdkBeta = Literal["context-1m-2025-08-07"]
Gunakan dengan field betas dalam ClaudeAgentOptions untuk mengaktifkan fitur beta.
Beta context-1m-2025-08-07 sudah pensiun sejak 30 April 2026. Melewatkan header ini dengan Claude Sonnet 4.5 atau Sonnet 4 tidak berpengaruh, dan permintaan yang melebihi jendela konteks standar 200k-token mengembalikan error. Untuk menggunakan jendela konteks 1M-token, migrasikan ke Claude Sonnet 4.6, Claude Opus 4.6, atau Claude Opus 4.7, yang mencakup konteks 1M pada harga standar tanpa header beta yang diperlukan.

McpSdkServerConfig

Konfigurasi untuk server MCP SDK yang dibuat dengan create_sdk_mcp_server().
class McpSdkServerConfig(TypedDict):
    type: Literal["sdk"]
    name: str
    instance: Any  # MCP Server instance

McpServerConfig

Tipe union untuk konfigurasi server MCP.
McpServerConfig = (
    McpStdioServerConfig | McpSSEServerConfig | McpHttpServerConfig | McpSdkServerConfig
)

McpStdioServerConfig

class McpStdioServerConfig(TypedDict):
    type: NotRequired[Literal["stdio"]]  # Optional for backwards compatibility
    command: str
    args: NotRequired[list[str]]
    env: NotRequired[dict[str, str]]

McpSSEServerConfig

class McpSSEServerConfig(TypedDict):
    type: Literal["sse"]
    url: str
    headers: NotRequired[dict[str, str]]

McpHttpServerConfig

class McpHttpServerConfig(TypedDict):
    type: Literal["http"]
    url: str
    headers: NotRequired[dict[str, str]]

McpServerStatusConfig

Konfigurasi server MCP seperti yang dilaporkan oleh get_mcp_status(). Ini adalah union dari semua varian transport McpServerConfig ditambah varian output-only claudeai-proxy untuk server yang di-proxy melalui claude.ai.
McpServerStatusConfig = (
    McpStdioServerConfig
    | McpSSEServerConfig
    | McpHttpServerConfig
    | McpSdkServerConfigStatus
    | McpClaudeAIProxyServerConfig
)
McpSdkServerConfigStatus adalah bentuk yang dapat diserialisasi dari McpSdkServerConfig dengan hanya field type ("sdk") dan name (str); instance dalam proses dihilangkan. McpClaudeAIProxyServerConfig memiliki field type ("claudeai-proxy"), url (str), dan id (str).

McpStatusResponse

Respons dari ClaudeSDKClient.get_mcp_status(). Membungkus daftar status server di bawah kunci mcpServers.
class McpStatusResponse(TypedDict):
    mcpServers: list[McpServerStatus]

McpServerStatus

Status server MCP yang terhubung, terdapat dalam McpStatusResponse.
class McpServerStatus(TypedDict):
    name: str
    status: McpServerConnectionStatus  # "connected" | "failed" | "needs-auth" | "pending" | "disabled"
    serverInfo: NotRequired[McpServerInfo]
    error: NotRequired[str]
    config: NotRequired[McpServerStatusConfig]
    scope: NotRequired[str]
    tools: NotRequired[list[McpToolInfo]]
FieldTipeDeskripsi
namestrNama server
statusstrSalah satu dari "connected", "failed", "needs-auth", "pending", atau "disabled"
serverInfodict (opsional)Nama dan versi server ({"name": str, "version": str})
errorstr (opsional)Pesan error jika server gagal terhubung
configMcpServerStatusConfig (opsional)Konfigurasi server. Bentuk yang sama seperti McpServerConfig (stdio, SSE, HTTP, atau SDK), ditambah varian claudeai-proxy untuk server yang terhubung melalui claude.ai
scopestr (opsional)Scope konfigurasi
toolslist (opsional)Tools yang disediakan oleh server ini, masing-masing dengan field name, description, dan annotations

SdkPluginConfig

Konfigurasi untuk memuat plugins dalam SDK.
class SdkPluginConfig(TypedDict):
    type: Literal["local"]
    path: str
FieldTipeDeskripsi
typeLiteral["local"]Harus "local" (hanya plugins lokal yang saat ini didukung)
pathstrJalur absolut atau relatif ke direktori plugin
Contoh:
plugins = [
    {"type": "local", "path": "./my-plugin"},
    {"type": "local", "path": "/absolute/path/to/plugin"},
]
Untuk informasi lengkap tentang membuat dan menggunakan plugins, lihat Plugins.

Tipe Pesan

Message

Tipe union dari semua pesan yang mungkin.
Message = (
    UserMessage
    | AssistantMessage
    | SystemMessage
    | ResultMessage
    | StreamEvent
    | RateLimitEvent
)

UserMessage

Pesan input pengguna.
@dataclass
class UserMessage:
    content: str | list[ContentBlock]
    uuid: str | None = None
    parent_tool_use_id: str | None = None
    tool_use_result: dict[str, Any] | None = None
FieldTipeDeskripsi
contentstr | list[ContentBlock]Konten pesan sebagai teks atau blok konten
uuidstr | NonePengenal pesan unik
parent_tool_use_idstr | NoneID penggunaan tool jika pesan ini adalah respons hasil tool
tool_use_resultdict[str, Any] | NoneData hasil tool jika berlaku

AssistantMessage

Pesan respons asisten dengan blok konten.
@dataclass
class AssistantMessage:
    content: list[ContentBlock]
    model: str
    parent_tool_use_id: str | None = None
    error: AssistantMessageError | None = None
    usage: dict[str, Any] | None = None
    message_id: str | None = None
FieldTipeDeskripsi
contentlist[ContentBlock]Daftar blok konten dalam respons
modelstrModel yang menghasilkan respons
parent_tool_use_idstr | NoneID penggunaan tool jika ini adalah respons bersarang
errorAssistantMessageError | NoneTipe error jika respons mengalami error
usagedict[str, Any] | NonePenggunaan token per-pesan (kunci yang sama seperti ResultMessage.usage)
message_idstr | NoneID pesan API. Beberapa pesan dari satu putaran berbagi ID yang sama

AssistantMessageError

Tipe error yang mungkin untuk pesan asisten.
AssistantMessageError = Literal[
    "authentication_failed",
    "billing_error",
    "rate_limit",
    "invalid_request",
    "server_error",
    "max_output_tokens",
    "unknown",
]

SystemMessage

Pesan sistem dengan metadata.
@dataclass
class SystemMessage:
    subtype: str
    data: dict[str, Any]

ResultMessage

Pesan hasil akhir dengan informasi biaya dan penggunaan.
@dataclass
class ResultMessage:
    subtype: str
    duration_ms: int
    duration_api_ms: int
    is_error: bool
    num_turns: int
    session_id: str
    stop_reason: str | None = None
    total_cost_usd: float | None = None
    usage: dict[str, Any] | None = None
    result: str | None = None
    structured_output: Any = None
    model_usage: dict[str, Any] | None = None
    permission_denials: list[Any] | None = None
    deferred_tool_use: DeferredToolUse | None = None
    errors: list[str] | None = None
    api_error_status: int | None = None
    uuid: str | None = None
Dict usage berisi kunci berikut ketika ada:
KunciTipeDeskripsi
input_tokensintTotal token input yang dikonsumsi.
output_tokensintTotal token output yang dihasilkan.
cache_creation_input_tokensintToken yang digunakan untuk membuat entri cache baru.
cache_read_input_tokensintToken yang dibaca dari entri cache yang ada.
Dict model_usage memetakan nama model ke penggunaan per-model. Kunci dict dalam menggunakan camelCase karena nilai diteruskan tanpa modifikasi dari proses CLI yang mendasar, cocok dengan tipe ModelUsage TypeScript:
KunciTipeDeskripsi
inputTokensintToken input untuk model ini.
outputTokensintToken output untuk model ini.
cacheReadInputTokensintToken baca cache untuk model ini.
cacheCreationInputTokensintToken pembuatan cache untuk model ini.
webSearchRequestsintPermintaan pencarian web yang dibuat oleh model ini.
costUSDfloatBiaya yang diperkirakan dalam USD untuk model ini, dihitung sisi klien. Lihat Track cost and usage untuk peringatan penagihan.
contextWindowintUkuran jendela konteks untuk model ini.
maxOutputTokensintBatas token output maksimal untuk model ini.

StreamEvent

Event stream untuk pembaruan pesan parsial selama streaming. Hanya diterima ketika include_partial_messages=True dalam ClaudeAgentOptions. Impor via from claude_agent_sdk.types import StreamEvent.
@dataclass
class StreamEvent:
    uuid: str
    session_id: str
    event: dict[str, Any]  # The raw Claude API stream event
    parent_tool_use_id: str | None = None
FieldTipeDeskripsi
uuidstrPengenal unik untuk event ini
session_idstrPengenal sesi
eventdict[str, Any]Data event stream Claude API mentah
parent_tool_use_idstr | NoneID penggunaan tool induk jika event ini dari subagent

RateLimitEvent

Dipancarkan ketika status rate limit berubah (misalnya, dari "allowed" ke "allowed_warning"). Gunakan ini untuk memperingatkan pengguna sebelum mereka mencapai batas keras, atau untuk mundur ketika status adalah "rejected".
@dataclass
class RateLimitEvent:
    rate_limit_info: RateLimitInfo
    uuid: str
    session_id: str
FieldTipeDeskripsi
rate_limit_infoRateLimitInfoStatus rate limit saat ini
uuidstrPengenal event unik
session_idstrPengenal sesi

RateLimitInfo

Status rate limit yang dibawa oleh RateLimitEvent.
RateLimitStatus = Literal["allowed", "allowed_warning", "rejected"]
RateLimitType = Literal[
    "five_hour", "seven_day", "seven_day_opus", "seven_day_sonnet", "overage"
]


@dataclass
class RateLimitInfo:
    status: RateLimitStatus
    resets_at: int | None = None
    rate_limit_type: RateLimitType | None = None
    utilization: float | None = None
    overage_status: RateLimitStatus | None = None
    overage_resets_at: int | None = None
    overage_disabled_reason: str | None = None
    raw: dict[str, Any] = field(default_factory=dict)
FieldTipeDeskripsi
statusRateLimitStatusStatus saat ini. "allowed_warning" berarti mendekati batas; "rejected" berarti batas tercapai
resets_atint | NoneTimestamp Unix ketika jendela rate limit direset
rate_limit_typeRateLimitType | NoneJendela rate limit mana yang berlaku
utilizationfloat | NoneFraksi rate limit yang dikonsumsi (0.0 hingga 1.0)
overage_statusRateLimitStatus | NoneStatus penggunaan overage pay-as-you-go, jika berlaku
overage_resets_atint | NoneTimestamp Unix ketika jendela overage direset
overage_disabled_reasonstr | NoneMengapa overage tidak tersedia, jika status adalah "rejected"
rawdict[str, Any]Dict mentah lengkap dari CLI, termasuk field yang tidak dimodelkan di atas

TaskStartedMessage

Dipancarkan ketika tugas latar belakang dimulai. Tugas latar belakang adalah apa pun yang dilacak di luar putaran utama: perintah Bash yang di-background, Monitor watch, subagent yang dihasilkan melalui tool Agent, atau agent jarak jauh. Field task_type memberi tahu Anda yang mana. Penamaan ini tidak terkait dengan penggantian nama tool Task-ke-Agent.
@dataclass
class TaskStartedMessage(SystemMessage):
    task_id: str
    description: str
    uuid: str
    session_id: str
    tool_use_id: str | None = None
    task_type: str | None = None
FieldTipeDeskripsi
task_idstrPengenal unik untuk tugas
descriptionstrDeskripsi tugas
uuidstrPengenal pesan unik
session_idstrPengenal sesi
tool_use_idstr | NoneID penggunaan tool yang terkait
task_typestr | NoneJenis tugas latar belakang: "local_bash" untuk Bash dan Monitor watches di background, "local_agent", atau "remote_agent"

TaskUsage

Data token dan timing untuk tugas latar belakang.
class TaskUsage(TypedDict):
    total_tokens: int
    tool_uses: int
    duration_ms: int

TaskProgressMessage

Dipancarkan secara berkala dengan pembaruan kemajuan untuk tugas latar belakang yang sedang berjalan.
@dataclass
class TaskProgressMessage(SystemMessage):
    task_id: str
    description: str
    usage: TaskUsage
    uuid: str
    session_id: str
    tool_use_id: str | None = None
    last_tool_name: str | None = None
FieldTipeDeskripsi
task_idstrPengenal unik untuk tugas
descriptionstrDeskripsi status saat ini
usageTaskUsagePenggunaan token untuk tugas ini sejauh ini
uuidstrPengenal pesan unik
session_idstrPengenal sesi
tool_use_idstr | NoneID penggunaan tool yang terkait
last_tool_namestr | NoneNama tool terakhir yang digunakan tugas

TaskNotificationMessage

Dipancarkan ketika tugas latar belakang selesai, gagal, atau dihentikan. Tugas latar belakang termasuk perintah Bash run_in_background, Monitor watches, dan subagent latar belakang.
@dataclass
class TaskNotificationMessage(SystemMessage):
    task_id: str
    status: TaskNotificationStatus  # "completed" | "failed" | "stopped"
    output_file: str
    summary: str
    uuid: str
    session_id: str
    tool_use_id: str | None = None
    usage: TaskUsage | None = None
FieldTipeDeskripsi
task_idstrPengenal unik untuk tugas
statusTaskNotificationStatusSalah satu dari "completed", "failed", atau "stopped"
output_filestrJalur ke file output tugas
summarystrRingkasan hasil tugas
uuidstrPengenal pesan unik
session_idstrPengenal sesi
tool_use_idstr | NoneID penggunaan tool yang terkait
usageTaskUsage | NonePenggunaan token akhir untuk tugas

Tipe Blok Konten

ContentBlock

Tipe union dari semua blok konten.
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock

TextBlock

Blok konten teks.
@dataclass
class TextBlock:
    text: str

ThinkingBlock

Blok konten thinking (untuk model dengan kemampuan thinking).
@dataclass
class ThinkingBlock:
    thinking: str
    signature: str

ToolUseBlock

Blok permintaan penggunaan tool.
@dataclass
class ToolUseBlock:
    id: str
    name: str
    input: dict[str, Any]

ToolResultBlock

Blok hasil eksekusi tool.
@dataclass
class ToolResultBlock:
    tool_use_id: str
    content: str | list[dict[str, Any]] | None = None
    is_error: bool | None = None

Tipe Error

ClaudeSDKError

Kelas exception dasar untuk semua error SDK.
class ClaudeSDKError(Exception):
    """Base error for Claude SDK."""

CLINotFoundError

Diangkat ketika Claude Code CLI tidak diinstal atau tidak ditemukan.
class CLINotFoundError(CLIConnectionError):
    def __init__(
        self, message: str = "Claude Code not found", cli_path: str | None = None
    ):
        """
        Args:
            message: Error message (default: "Claude Code not found")
            cli_path: Optional path to the CLI that was not found
        """

CLIConnectionError

Diangkat ketika koneksi ke Claude Code gagal.
class CLIConnectionError(ClaudeSDKError):
    """Failed to connect to Claude Code."""

ProcessError

Diangkat ketika proses Claude Code gagal.
class ProcessError(ClaudeSDKError):
    def __init__(
        self, message: str, exit_code: int | None = None, stderr: str | None = None
    ):
        self.exit_code = exit_code
        self.stderr = stderr

CLIJSONDecodeError

Diangkat ketika parsing JSON gagal.
class CLIJSONDecodeError(ClaudeSDKError):
    def __init__(self, line: str, original_error: Exception):
        """
        Args:
            line: The line that failed to parse
            original_error: The original JSON decode exception
        """
        self.line = line
        self.original_error = original_error

Tipe Hook

Untuk panduan komprehensif tentang menggunakan hooks dengan contoh dan pola umum, lihat Hooks guide.

HookEvent

Tipe event hook yang didukung.
HookEvent = Literal[
    "PreToolUse",  # Called before tool execution
    "PostToolUse",  # Called after tool execution
    "PostToolUseFailure",  # Called when a tool execution fails
    "UserPromptSubmit",  # Called when user submits a prompt
    "Stop",  # Called when stopping execution
    "SubagentStop",  # Called when a subagent stops
    "PreCompact",  # Called before message compaction
    "Notification",  # Called for notification events
    "SubagentStart",  # Called when a subagent starts
    "PermissionRequest",  # Called when a permission decision is needed
]
SDK TypeScript mendukung event hook tambahan yang belum tersedia di Python: SessionStart, SessionEnd, Setup, TeammateIdle, TaskCompleted, ConfigChange, WorktreeCreate, WorktreeRemove, PostToolBatch, dan MessageDisplay.

HookCallback

Definisi tipe untuk fungsi callback hook.
HookCallback = Callable[[HookInput, str | None, HookContext], Awaitable[HookJSONOutput]]
Parameter:
  • input: Input hook yang kuat dengan union yang dibedakan berdasarkan hook_event_name (lihat HookInput)
  • tool_use_id: Pengenal penggunaan tool opsional (untuk hook terkait tool)
  • context: Konteks hook dengan informasi tambahan
Mengembalikan HookJSONOutput yang mungkin berisi:
  • decision: "block" untuk memblokir tindakan
  • systemMessage: Pesan peringatan yang ditampilkan kepada pengguna
  • hookSpecificOutput: Data output spesifik hook

HookContext

Informasi konteks yang diteruskan ke callback hook.
class HookContext(TypedDict):
    signal: Any | None  # Future: abort signal support

HookMatcher

Konfigurasi untuk mencocokkan hooks ke event atau tools tertentu.
@dataclass
class HookMatcher:
    matcher: str | None = (
        None  # Tool name or pattern to match (e.g., "Bash", "Write|Edit")
    )
    hooks: list[HookCallback] = field(
        default_factory=list
    )  # List of callbacks to execute
    timeout: float | None = (
        None  # Timeout in seconds for all hooks in this matcher (default: 60)
    )

HookInput

Tipe union dari semua tipe input hook. Tipe aktual bergantung pada field hook_event_name.
HookInput = (
    PreToolUseHookInput
    | PostToolUseHookInput
    | PostToolUseFailureHookInput
    | UserPromptSubmitHookInput
    | StopHookInput
    | SubagentStopHookInput
    | PreCompactHookInput
    | NotificationHookInput
    | SubagentStartHookInput
    | PermissionRequestHookInput
)

BaseHookInput

Field dasar yang ada di semua tipe input hook.
class BaseHookInput(TypedDict):
    session_id: str
    transcript_path: str
    cwd: str
    permission_mode: NotRequired[str]
FieldTipeDeskripsi
session_idstrPengenal sesi saat ini
transcript_pathstrJalur ke file transkrip sesi
cwdstrDirektori kerja saat ini
permission_modestr (opsional)Mode izin saat ini

PreToolUseHookInput

Data input untuk event hook PreToolUse.
class PreToolUseHookInput(BaseHookInput):
    hook_event_name: Literal["PreToolUse"]
    tool_name: str
    tool_input: dict[str, Any]
    tool_use_id: str
    agent_id: NotRequired[str]
    agent_type: NotRequired[str]
FieldTipeDeskripsi
hook_event_nameLiteral["PreToolUse"]Selalu “PreToolUse”
tool_namestrNama tool yang akan dieksekusi
tool_inputdict[str, Any]Parameter input untuk tool
tool_use_idstrPengenal unik untuk penggunaan tool ini
agent_idstr (opsional)Pengenal subagent, ada ketika hook menyala di dalam subagent
agent_typestr (opsional)Tipe subagent, ada ketika hook menyala di dalam subagent

PostToolUseHookInput

Data input untuk event hook PostToolUse.
class PostToolUseHookInput(BaseHookInput):
    hook_event_name: Literal["PostToolUse"]
    tool_name: str
    tool_input: dict[str, Any]
    tool_response: Any
    tool_use_id: str
    agent_id: NotRequired[str]
    agent_type: NotRequired[str]
FieldTipeDeskripsi
hook_event_nameLiteral["PostToolUse"]Selalu “PostToolUse”
tool_namestrNama tool yang dieksekusi
tool_inputdict[str, Any]Parameter input yang digunakan
tool_responseAnyRespons dari eksekusi tool
tool_use_idstrPengenal unik untuk penggunaan tool ini
agent_idstr (opsional)Pengenal subagent, ada ketika hook menyala di dalam subagent
agent_typestr (opsional)Tipe subagent, ada ketika hook menyala di dalam subagent

PostToolUseFailureHookInput

Data input untuk event hook PostToolUseFailure. Dipanggil ketika eksekusi tool gagal.
class PostToolUseFailureHookInput(BaseHookInput):
    hook_event_name: Literal["PostToolUseFailure"]
    tool_name: str
    tool_input: dict[str, Any]
    tool_use_id: str
    error: str
    is_interrupt: NotRequired[bool]
    agent_id: NotRequired[str]
    agent_type: NotRequired[str]
FieldTipeDeskripsi
hook_event_nameLiteral["PostToolUseFailure"]Selalu “PostToolUseFailure”
tool_namestrNama tool yang gagal
tool_inputdict[str, Any]Parameter input yang digunakan
tool_use_idstrPengenal unik untuk penggunaan tool ini
errorstrPesan error dari eksekusi yang gagal
is_interruptbool (opsional)Apakah kegagalan disebabkan oleh interrupt
agent_idstr (opsional)Pengenal subagent, ada ketika hook menyala di dalam subagent
agent_typestr (opsional)Tipe subagent, ada ketika hook menyala di dalam subagent

UserPromptSubmitHookInput

Data input untuk event hook UserPromptSubmit.
class UserPromptSubmitHookInput(BaseHookInput):
    hook_event_name: Literal["UserPromptSubmit"]
    prompt: str
FieldTipeDeskripsi
hook_event_nameLiteral["UserPromptSubmit"]Selalu “UserPromptSubmit”
promptstrPrompt yang dikirimkan pengguna

StopHookInput

Data input untuk event hook Stop.
class StopHookInput(BaseHookInput):
    hook_event_name: Literal["Stop"]
    stop_hook_active: bool
FieldTipeDeskripsi
hook_event_nameLiteral["Stop"]Selalu “Stop”
stop_hook_activeboolApakah stop hook aktif

SubagentStopHookInput

Data input untuk event hook SubagentStop.
class SubagentStopHookInput(BaseHookInput):
    hook_event_name: Literal["SubagentStop"]
    stop_hook_active: bool
    agent_id: str
    agent_transcript_path: str
    agent_type: str
FieldTipeDeskripsi
hook_event_nameLiteral["SubagentStop"]Selalu “SubagentStop”
stop_hook_activeboolApakah stop hook aktif
agent_idstrPengenal unik untuk subagent
agent_transcript_pathstrJalur ke file transkrip subagent
agent_typestrTipe subagent

PreCompactHookInput

Data input untuk event hook PreCompact.
class PreCompactHookInput(BaseHookInput):
    hook_event_name: Literal["PreCompact"]
    trigger: Literal["manual", "auto"]
    custom_instructions: str | None
FieldTipeDeskripsi
hook_event_nameLiteral["PreCompact"]Selalu “PreCompact”
triggerLiteral["manual", "auto"]Apa yang memicu pemadatan
custom_instructionsstr | NoneInstruksi kustom untuk pemadatan

NotificationHookInput

Data input untuk event hook Notification.
class NotificationHookInput(BaseHookInput):
    hook_event_name: Literal["Notification"]
    message: str
    title: NotRequired[str]
    notification_type: str
FieldTipeDeskripsi
hook_event_nameLiteral["Notification"]Selalu “Notification”
messagestrKonten pesan notifikasi
titlestr (opsional)Judul notifikasi
notification_typestrTipe notifikasi

SubagentStartHookInput

Data input untuk event hook SubagentStart.
class SubagentStartHookInput(BaseHookInput):
    hook_event_name: Literal["SubagentStart"]
    agent_id: str
    agent_type: str
FieldTipeDeskripsi
hook_event_nameLiteral["SubagentStart"]Selalu “SubagentStart”
agent_idstrPengenal unik untuk subagent
agent_typestrTipe subagent

PermissionRequestHookInput

Data input untuk event hook PermissionRequest. Memungkinkan hooks untuk menangani keputusan izin secara programatis.
class PermissionRequestHookInput(BaseHookInput):
    hook_event_name: Literal["PermissionRequest"]
    tool_name: str
    tool_input: dict[str, Any]
    permission_suggestions: NotRequired[list[Any]]
FieldTipeDeskripsi
hook_event_nameLiteral["PermissionRequest"]Selalu “PermissionRequest”
tool_namestrNama tool yang meminta izin
tool_inputdict[str, Any]Parameter input untuk tool
permission_suggestionslist[Any] (opsional)Saran pembaruan izin dari CLI

HookJSONOutput

Tipe union untuk nilai pengembalian callback hook.
HookJSONOutput = AsyncHookJSONOutput | SyncHookJSONOutput

SyncHookJSONOutput

Output hook sinkron dengan field kontrol dan keputusan.
class SyncHookJSONOutput(TypedDict):
    # Control fields
    continue_: NotRequired[bool]  # Whether to proceed (default: True)
    suppressOutput: NotRequired[bool]  # Hide stdout from transcript
    stopReason: NotRequired[str]  # Message when continue is False

    # Decision fields
    decision: NotRequired[Literal["block"]]
    systemMessage: NotRequired[str]  # Warning message for user
    reason: NotRequired[str]  # Feedback for Claude

    # Hook-specific output
    hookSpecificOutput: NotRequired[HookSpecificOutput]
Gunakan continue_ (dengan underscore) dalam kode Python. Ini secara otomatis dikonversi ke continue ketika dikirim ke CLI.

HookSpecificOutput

TypedDict yang berisi nama event hook dan field spesifik event. Bentuknya bergantung pada nilai hookEventName. Untuk detail lengkap tentang field yang tersedia per event hook, lihat Control execution with hooks. Union yang dibedakan dari tipe output spesifik event. Field hookEventName menentukan field mana yang valid.
class PreToolUseHookSpecificOutput(TypedDict):
    hookEventName: Literal["PreToolUse"]
    permissionDecision: NotRequired[Literal["allow", "deny", "ask", "defer"]]
    permissionDecisionReason: NotRequired[str]
    updatedInput: NotRequired[dict[str, Any]]
    additionalContext: NotRequired[str]


class PostToolUseHookSpecificOutput(TypedDict):
    hookEventName: Literal["PostToolUse"]
    additionalContext: NotRequired[str]
    updatedToolOutput: NotRequired[Any]
    updatedMCPToolOutput: NotRequired[Any]  # Deprecated: use updatedToolOutput, which works for all tools


class PostToolUseFailureHookSpecificOutput(TypedDict):
    hookEventName: Literal["PostToolUseFailure"]
    additionalContext: NotRequired[str]


class UserPromptSubmitHookSpecificOutput(TypedDict):
    hookEventName: Literal["UserPromptSubmit"]
    additionalContext: NotRequired[str]


class NotificationHookSpecificOutput(TypedDict):
    hookEventName: Literal["Notification"]
    additionalContext: NotRequired[str]


class SubagentStartHookSpecificOutput(TypedDict):
    hookEventName: Literal["SubagentStart"]
    additionalContext: NotRequired[str]


class PermissionRequestHookSpecificOutput(TypedDict):
    hookEventName: Literal["PermissionRequest"]
    decision: dict[str, Any]


HookSpecificOutput = (
    PreToolUseHookSpecificOutput
    | PostToolUseHookSpecificOutput
    | PostToolUseFailureHookSpecificOutput
    | UserPromptSubmitHookSpecificOutput
    | NotificationHookSpecificOutput
    | SubagentStartHookSpecificOutput
    | PermissionRequestHookSpecificOutput
)

AsyncHookJSONOutput

Output hook async yang menunda eksekusi hook.
class AsyncHookJSONOutput(TypedDict):
    async_: Literal[True]  # Set to True to defer execution
    asyncTimeout: NotRequired[int]  # Timeout in milliseconds
Gunakan async_ (dengan underscore) dalam kode Python. Ini secara otomatis dikonversi ke async ketika dikirim ke CLI.

Contoh Penggunaan Hook

Contoh ini mendaftarkan dua hooks: satu yang memblokir perintah bash berbahaya seperti rm -rf /, dan satu lagi yang mencatat semua penggunaan tool untuk audit. Hook keamanan hanya berjalan pada perintah Bash (melalui matcher), sementara hook logging berjalan pada semua tools.
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, HookContext
from typing import Any


async def validate_bash_command(
    input_data: dict[str, Any], tool_use_id: str | None, context: HookContext
) -> dict[str, Any]:
    """Validate and potentially block dangerous bash commands."""
    if input_data["tool_name"] == "Bash":
        command = input_data["tool_input"].get("command", "")
        if "rm -rf /" in command:
            return {
                "hookSpecificOutput": {
                    "hookEventName": "PreToolUse",
                    "permissionDecision": "deny",
                    "permissionDecisionReason": "Dangerous command blocked",
                }
            }
    return {}


async def log_tool_use(
    input_data: dict[str, Any], tool_use_id: str | None, context: HookContext
) -> dict[str, Any]:
    """Log all tool usage for auditing."""
    print(f"Tool used: {input_data.get('tool_name')}")
    return {}


options = ClaudeAgentOptions(
    hooks={
        "PreToolUse": [
            HookMatcher(
                matcher="Bash", hooks=[validate_bash_command], timeout=120
            ),  # 2 min for validation
            HookMatcher(
                hooks=[log_tool_use]
            ),  # Applies to all tools (default 60s timeout)
        ],
        "PostToolUse": [HookMatcher(hooks=[log_tool_use])],
    }
)

async for message in query(prompt="Analyze this codebase", options=options):
    print(message)

Tipe Input/Output Tool

Dokumentasi skema input/output untuk semua tools Claude Code bawaan. Meskipun Python SDK tidak mengekspor ini sebagai tipe, mereka mewakili struktur input dan output tool dalam pesan.

Agent

Nama tool: Agent (sebelumnya Task, yang masih diterima sebagai alias) Input:
{
    "description": str,  # Deskripsi singkat tugas (3-5 kata)
    "prompt": str,  # Tugas untuk dijalankan oleh agen
    "subagent_type": str,  # Jenis agen khusus yang digunakan
}
Output:
{
    "result": str,  # Hasil akhir dari subagen
    "usage": dict | None,  # Statistik penggunaan token
    "total_cost_usd": float | None,  # Perkiraan biaya total dalam USD
    "duration_ms": int | None,  # Durasi eksekusi dalam milidetik
}

AskUserQuestion

Nama tool: AskUserQuestion Mengajukan pertanyaan klarifikasi kepada pengguna selama eksekusi. Lihat Handle approvals and user input untuk detail penggunaan. Input:
{
    "questions": [  # Pertanyaan untuk ditanyakan kepada pengguna (1-4 pertanyaan)
        {
            "question": str,  # Pertanyaan lengkap untuk ditanyakan kepada pengguna
            "header": str,  # Label sangat singkat ditampilkan sebagai chip/tag (maks 12 karakter)
            "options": [  # Pilihan yang tersedia (2-4 opsi)
                {
                    "label": str,  # Teks tampilan untuk opsi ini (1-5 kata)
                    "description": str,  # Penjelasan tentang arti opsi ini
                }
            ],
            "multiSelect": bool,  # Atur ke true untuk memungkinkan beberapa pilihan
        }
    ],
    "answers": dict[str, str | list[str]] | None,
    # Jawaban pengguna diisi oleh sistem izin. Jawaban multi-pilih
    # mungkin berupa daftar label atau string yang digabungkan dengan koma
}
Output:
{
    "questions": [  # Pertanyaan yang diajukan
        {
            "question": str,
            "header": str,
            "options": [{"label": str, "description": str}],
            "multiSelect": bool,
        }
    ],
    "answers": dict[str, str],  # Memetakan teks pertanyaan ke string jawaban
    # Jawaban multi-pilih dipisahkan dengan koma
}

Bash

Nama tool: Bash Input:
{
    "command": str,  # Perintah yang akan dijalankan
    "timeout": int | None,  # Waktu tunggu opsional dalam milidetik (maks 600000)
    "description": str | None,  # Deskripsi jelas dan ringkas (5-10 kata)
    "run_in_background": bool | None,  # Atur ke true untuk menjalankan di latar belakang
}
Output:
{
    "output": str,  # Output stdout dan stderr gabungan
    "exitCode": int,  # Kode keluar perintah
    "killed": bool | None,  # Apakah perintah dibunuh karena waktu tunggu
    "shellId": str | None,  # ID Shell untuk proses latar belakang
}

Monitor

Nama tool: Monitor Menjalankan skrip latar belakang dan mengirimkan setiap baris stdout ke Claude sebagai event sehingga dapat bereaksi tanpa polling. Monitor mengikuti aturan izin yang sama seperti Bash. Lihat Monitor tool reference untuk perilaku dan ketersediaan penyedia. Input:
{
    "command": str,  # Skrip shell; setiap baris stdout adalah event, keluar mengakhiri pengawasan
    "description": str,  # Deskripsi singkat ditampilkan dalam notifikasi
    "timeout_ms": int | None,  # Bunuh setelah batas waktu ini (default 300000, maks 3600000)
    "persistent": bool | None,  # Jalankan untuk seumur hidup sesi; hentikan dengan TaskStop
}
Output:
{
    "taskId": str,  # ID tugas monitor latar belakang
    "timeoutMs": int,  # Batas waktu dalam milidetik (0 saat persistent)
    "persistent": bool | None,  # True saat berjalan hingga TaskStop atau akhir sesi
}

Edit

Nama tool: Edit Input:
{
    "file_path": str,  # Jalur absolut ke file yang akan dimodifikasi
    "old_string": str,  # Teks yang akan diganti
    "new_string": str,  # Teks untuk menggantinya
    "replace_all": bool | None,  # Ganti semua kemunculan (default False)
}
Output:
{
    "message": str,  # Pesan konfirmasi
    "replacements": int,  # Jumlah penggantian yang dilakukan
    "file_path": str,  # Jalur file yang diedit
}

Read

Nama tool: Read Input:
{
    "file_path": str,  # Jalur absolut ke file yang akan dibaca
    "offset": int | None,  # Nomor baris untuk mulai membaca dari
    "limit": int | None,  # Jumlah baris yang akan dibaca
}
Output (File teks):
{
    "content": str,  # Isi file dengan nomor baris
    "total_lines": int,  # Total jumlah baris dalam file
    "lines_returned": int,  # Baris yang benar-benar dikembalikan
}
Output (Gambar):
{
    "image": str,  # Data gambar yang dikodekan Base64
    "mime_type": str,  # Tipe MIME gambar
    "file_size": int,  # Ukuran file dalam byte
}

Write

Nama tool: Write Input:
{
    "file_path": str,  # Jalur absolut ke file yang akan ditulis
    "content": str,  # Konten yang akan ditulis ke file
}
Output:
{
    "message": str,  # Pesan sukses
    "bytes_written": int,  # Jumlah byte yang ditulis
    "file_path": str,  # Jalur file yang ditulis
}

Glob

Nama tool: Glob Input:
{
    "pattern": str,  # Pola glob untuk mencocokkan file
    "path": str | None,  # Direktori untuk dicari (default ke cwd)
}
Output:
{
    "matches": list[str],  # Array jalur file yang cocok
    "count": int,  # Jumlah kecocokan yang ditemukan
    "search_path": str,  # Direktori pencarian yang digunakan
}

Grep

Nama tool: Grep Input:
{
    "pattern": str,  # Pola ekspresi reguler
    "path": str | None,  # File atau direktori untuk dicari
    "glob": str | None,  # Pola glob untuk menyaring file
    "type": str | None,  # Jenis file untuk dicari
    "output_mode": str | None,  # "content", "files_with_matches", atau "count"
    "-i": bool | None,  # Pencarian tidak peka huruf besar-kecil
    "-n": bool | None,  # Tampilkan nomor baris
    "-B": int | None,  # Baris untuk ditampilkan sebelum setiap kecocokan
    "-A": int | None,  # Baris untuk ditampilkan setelah setiap kecocokan
    "-C": int | None,  # Baris untuk ditampilkan sebelum dan sesudah
    "head_limit": int | None,  # Batasi output ke N baris/entri pertama
    "multiline": bool | None,  # Aktifkan mode multiline
}
Output (content mode):
{
    "matches": [
        {
            "file": str,
            "line_number": int | None,
            "line": str,
            "before_context": list[str] | None,
            "after_context": list[str] | None,
        }
    ],
    "total_matches": int,
}
Output (files_with_matches mode):
{
    "files": list[str],  # File yang berisi kecocokan
    "count": int,  # Jumlah file dengan kecocokan
}

NotebookEdit

Nama tool: NotebookEdit Input:
{
    "notebook_path": str,  # Jalur absolut ke notebook Jupyter
    "cell_id": str | None,  # ID sel yang akan diedit
    "new_source": str,  # Sumber baru untuk sel
    "cell_type": "code" | "markdown" | None,  # Jenis sel
    "edit_mode": "replace" | "insert" | "delete" | None,  # Jenis operasi edit
}
Output:
{
    "message": str,  # Pesan sukses
    "edit_type": "replaced" | "inserted" | "deleted",  # Jenis edit yang dilakukan
    "cell_id": str | None,  # ID sel yang terpengaruh
    "total_cells": int,  # Total sel dalam notebook setelah edit
}

WebFetch

Nama tool: WebFetch Input:
{
    "url": str,  # URL untuk mengambil konten dari
    "prompt": str,  # Prompt untuk dijalankan pada konten yang diambil
}
Output:
{
    "bytes": int,  # Ukuran konten yang diambil dalam byte
    "code": int,  # Kode respons HTTP
    "codeText": str,  # Teks kode respons HTTP
    "result": str,  # Hasil yang diproses dari menerapkan prompt ke konten
    "durationMs": int,  # Waktu untuk mengambil dan memproses konten, dalam milidetik
    "url": str,  # URL yang diambil
}

WebSearch

Nama tool: WebSearch Input:
{
    "query": str,  # Kueri pencarian yang digunakan
    "allowed_domains": list[str] | None,  # Hanya sertakan hasil dari domain ini
    "blocked_domains": list[str] | None,  # Jangan pernah sertakan hasil dari domain ini
}
Output:
{
    "query": str,  # Kueri pencarian
    "results": list[str | {"tool_use_id": str, "content": list[{"title": str, "url": str}]}],
    "durationSeconds": float,  # Durasi pencarian dalam detik
}

TodoWrite

Nama tool: TodoWrite
Mulai dari Claude Code v2.1.142, TodoWrite dinonaktifkan secara default. Gunakan TaskCreate, TaskGet, TaskUpdate, dan TaskList sebagai gantinya. Lihat Migrate to Task tools untuk memperbarui kode pemantauan Anda, atau atur CLAUDE_CODE_ENABLE_TASKS=0 untuk kembali ke TodoWrite.
Input:
{
    "todos": [
        {
            "content": str,  # Deskripsi tugas
            "status": "pending" | "in_progress" | "completed",  # Status tugas
            "activeForm": str,  # Bentuk aktif deskripsi
        }
    ]
}
Output:
{
    "message": str,  # Pesan sukses
    "stats": {"total": int, "pending": int, "in_progress": int, "completed": int},
}

TaskCreate

Nama tool: TaskCreate Input:
{
    "subject": str,  # Judul tugas singkat
    "description": str,  # Badan tugas terperinci
    "activeForm": str | None,  # Label bentuk present-tense ditampilkan saat sedang berlangsung
    "metadata": dict | None,  # Metadata pemanggil arbitrer
}
Output:
{
    "task": {"id": str, "subject": str},  # Tugas yang dibuat dengan ID yang ditugaskan
}

TaskUpdate

Nama tool: TaskUpdate Input:
{
    "taskId": str,  # ID tugas yang akan dipatch
    "status": Literal["pending", "in_progress", "completed", "deleted"] | None,
    "subject": str | None,
    "description": str | None,
    "activeForm": str | None,
    "addBlocks": list[str] | None,  # ID tugas yang sekarang diblokir oleh tugas ini
    "addBlockedBy": list[str] | None,  # ID tugas yang sekarang memblokir tugas ini
    "owner": str | None,
    "metadata": dict | None,
}
Output:
{
    "success": bool,
    "taskId": str,
    "updatedFields": list[str],  # Nama bidang yang berubah
    "error": str | None,
    "statusChange": {"from": str, "to": str} | None,
}

TaskGet

Nama tool: TaskGet Input:
{
    "taskId": str,  # ID tugas yang akan dibaca
}
Output:
{
    "task": {
        "id": str,
        "subject": str,
        "description": str,
        "status": Literal["pending", "in_progress", "completed"],
        "blocks": list[str],
        "blockedBy": list[str],
    } | None,  # None saat ID tidak ditemukan
}

TaskList

Nama tool: TaskList Input:
{}
Output:
{
    "tasks": [
        {
            "id": str,
            "subject": str,
            "status": Literal["pending", "in_progress", "completed"],
            "owner": str | None,
            "blockedBy": list[str],
        }
    ],
}

BashOutput

Nama tool: BashOutput Input:
{
    "bash_id": str,  # ID shell latar belakang
    "filter": str | None,  # Regex opsional untuk menyaring baris output
}
Output:
{
    "output": str,  # Output baru sejak pemeriksaan terakhir
    "status": "running" | "completed" | "failed",  # Status shell saat ini
    "exitCode": int | None,  # Kode keluar saat selesai
}

KillBash

Nama tool: KillBash Input:
{
    "shell_id": str  # ID shell latar belakang yang akan dibunuh
}
Output:
{
    "message": str,  # Pesan sukses
    "shell_id": str,  # ID shell yang dibunuh
}

ExitPlanMode

Nama tool: ExitPlanMode Input:
{
    "plan": str  # Rencana yang akan dijalankan oleh pengguna untuk persetujuan
}
Output:
{
    "message": str,  # Pesan konfirmasi
    "approved": bool | None,  # Apakah pengguna menyetujui rencana
}

ListMcpResources

Nama tool: ListMcpResourcesTool Input:
{
    "server": str | None  # Nama server opsional untuk menyaring sumber daya
}
Output:
{
    "resources": [
        {
            "uri": str,
            "name": str,
            "description": str | None,
            "mimeType": str | None,
            "server": str,
        }
    ],
    "total": int,
}

ReadMcpResource

Nama tool: ReadMcpResourceTool Input:
{
    "server": str,  # Nama server MCP
    "uri": str,  # URI sumber daya yang akan dibaca
}
Output:
{
    "contents": [
        {"uri": str, "mimeType": str | None, "text": str | None, "blob": str | None}
    ],
    "server": str,
}

Fitur Lanjutan dengan ClaudeSDKClient

Membangun Antarmuka Percakapan Berkelanjutan

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    AssistantMessage,
    TextBlock,
)
import asyncio


class ConversationSession:
    """Maintains a single conversation session with Claude."""

    def __init__(self, options: ClaudeAgentOptions | None = None):
        self.client = ClaudeSDKClient(options)
        self.turn_count = 0

    async def start(self):
        await self.client.connect()
        print("Starting conversation session. Claude will remember context.")
        print(
            "Commands: 'exit' to quit, 'interrupt' to stop current task, 'new' for new session"
        )

        while True:
            user_input = input(f"\n[Turn {self.turn_count + 1}] You: ")

            if user_input.lower() == "exit":
                break
            elif user_input.lower() == "interrupt":
                await self.client.interrupt()
                print("Task interrupted!")
                continue
            elif user_input.lower() == "new":
                # Disconnect and reconnect for a fresh session
                await self.client.disconnect()
                await self.client.connect()
                self.turn_count = 0
                print("Started new conversation session (previous context cleared)")
                continue

            # Send message - the session retains all previous messages
            await self.client.query(user_input)
            self.turn_count += 1

            # Process response
            print(f"[Turn {self.turn_count}] Claude: ", end="")
            async for message in self.client.receive_response():
                if isinstance(message, AssistantMessage):
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(block.text, end="")
            print()  # New line after response

        await self.client.disconnect()
        print(f"Conversation ended after {self.turn_count} turns.")


async def main():
    options = ClaudeAgentOptions(
        allowed_tools=["Read", "Write", "Bash"], permission_mode="acceptEdits"
    )
    session = ConversationSession(options)
    await session.start()


# Example conversation:
# Turn 1 - You: "Create a file called hello.py"
# Turn 1 - Claude: "I'll create a hello.py file for you..."
# Turn 2 - You: "What's in that file?"
# Turn 2 - Claude: "The hello.py file I just created contains..." (remembers!)
# Turn 3 - You: "Add a main function to it"
# Turn 3 - Claude: "I'll add a main function to hello.py..." (knows which file!)

asyncio.run(main())

Menggunakan Hooks untuk Modifikasi Perilaku

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    HookMatcher,
    HookContext,
)
import asyncio
from typing import Any


async def pre_tool_logger(
    input_data: dict[str, Any], tool_use_id: str | None, context: HookContext
) -> dict[str, Any]:
    """Log all tool usage before execution."""
    tool_name = input_data.get("tool_name", "unknown")
    print(f"[PRE-TOOL] About to use: {tool_name}")

    # You can modify or block the tool execution here
    if tool_name == "Bash" and "rm -rf" in str(input_data.get("tool_input", {})):
        return {
            "hookSpecificOutput": {
                "hookEventName": "PreToolUse",
                "permissionDecision": "deny",
                "permissionDecisionReason": "Dangerous command blocked",
            }
        }
    return {}


async def post_tool_logger(
    input_data: dict[str, Any], tool_use_id: str | None, context: HookContext
) -> dict[str, Any]:
    """Log results after tool execution."""
    tool_name = input_data.get("tool_name", "unknown")
    print(f"[POST-TOOL] Completed: {tool_name}")
    return {}


async def user_prompt_modifier(
    input_data: dict[str, Any], tool_use_id: str | None, context: HookContext
) -> dict[str, Any]:
    """Add context to user prompts."""
    original_prompt = input_data.get("prompt", "")

    # Add a timestamp as additional context for Claude to see
    from datetime import datetime

    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    return {
        "hookSpecificOutput": {
            "hookEventName": "UserPromptSubmit",
            "additionalContext": f"[Submitted at {timestamp}] Original prompt: {original_prompt}",
        }
    }


async def main():
    options = ClaudeAgentOptions(
        hooks={
            "PreToolUse": [
                HookMatcher(hooks=[pre_tool_logger]),
                HookMatcher(matcher="Bash", hooks=[pre_tool_logger]),
            ],
            "PostToolUse": [HookMatcher(hooks=[post_tool_logger])],
            "UserPromptSubmit": [HookMatcher(hooks=[user_prompt_modifier])],
        },
        allowed_tools=["Read", "Write", "Bash"],
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("List files in current directory")

        async for message in client.receive_response():
            # Hooks will automatically log tool usage
            pass


asyncio.run(main())

Pemantauan Kemajuan Real-time

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    AssistantMessage,
    ToolUseBlock,
    ToolResultBlock,
    TextBlock,
)
import asyncio


async def monitor_progress():
    options = ClaudeAgentOptions(
        allowed_tools=["Write", "Bash"], permission_mode="acceptEdits"
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Create 5 Python files with different sorting algorithms")

        # Monitor progress in real-time
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, ToolUseBlock):
                        if block.name == "Write":
                            file_path = block.input.get("file_path", "")
                            print(f"Creating: {file_path}")
                    elif isinstance(block, ToolResultBlock):
                        print("Completed tool execution")
                    elif isinstance(block, TextBlock):
                        print(f"Claude says: {block.text[:100]}...")

        print("Task completed!")


asyncio.run(monitor_progress())

Contoh Penggunaan

Operasi file dasar (menggunakan query)

from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock
import asyncio


async def create_project():
    options = ClaudeAgentOptions(
        allowed_tools=["Read", "Write", "Bash"],
        permission_mode="acceptEdits",
        cwd="/home/user/project",
    )

    async for message in query(
        prompt="Create a Python project structure with setup.py", options=options
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, ToolUseBlock):
                    print(f"Using tool: {block.name}")


asyncio.run(create_project())

Penanganan error

from claude_agent_sdk import query, CLINotFoundError, ProcessError, CLIJSONDecodeError

try:
    async for message in query(prompt="Hello"):
        print(message)
except CLINotFoundError:
    print(
        "Claude Code CLI not found. Try reinstalling: pip install --force-reinstall claude-agent-sdk"
    )
except ProcessError as e:
    print(f"Process failed with exit code: {e.exit_code}")
except CLIJSONDecodeError as e:
    print(f"Failed to parse response: {e}")

Mode streaming dengan klien

from claude_agent_sdk import ClaudeSDKClient
import asyncio


async def interactive_session():
    async with ClaudeSDKClient() as client:
        # Send initial message
        await client.query("What's the weather like?")

        # Process responses
        async for msg in client.receive_response():
            print(msg)

        # Send follow-up
        await client.query("Tell me more about that")

        # Process follow-up response
        async for msg in client.receive_response():
            print(msg)


asyncio.run(interactive_session())

Menggunakan tools kustom dengan ClaudeSDKClient

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    tool,
    create_sdk_mcp_server,
    AssistantMessage,
    TextBlock,
)
import asyncio
from typing import Any


# Define custom tools with @tool decorator
@tool("calculate", "Perform mathematical calculations", {"expression": str})
async def calculate(args: dict[str, Any]) -> dict[str, Any]:
    try:
        result = eval(args["expression"], {"__builtins__": {}})
        return {"content": [{"type": "text", "text": f"Result: {result}"}]}
    except Exception as e:
        return {
            "content": [{"type": "text", "text": f"Error: {str(e)}"}],
            "is_error": True,
        }


@tool("get_time", "Get current time", {})
async def get_time(args: dict[str, Any]) -> dict[str, Any]:
    from datetime import datetime

    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    return {"content": [{"type": "text", "text": f"Current time: {current_time}"}]}


async def main():
    # Create SDK MCP server with custom tools
    my_server = create_sdk_mcp_server(
        name="utilities", version="1.0.0", tools=[calculate, get_time]
    )

    # Configure options with the server
    options = ClaudeAgentOptions(
        mcp_servers={"utils": my_server},
        allowed_tools=["mcp__utils__calculate", "mcp__utils__get_time"],
    )

    # Use ClaudeSDKClient for interactive tool usage
    async with ClaudeSDKClient(options=options) as client:
        await client.query("What's 123 * 456?")

        # Process calculation response
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Calculation: {block.text}")

        # Follow up with time query
        await client.query("What time is it now?")

        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Time: {block.text}")


asyncio.run(main())

Konfigurasi Sandbox

SandboxSettings

Konfigurasi untuk perilaku sandbox. Gunakan ini untuk mengaktifkan sandboxing perintah dan mengonfigurasi pembatasan jaringan secara programatis.
class SandboxSettings(TypedDict, total=False):
    enabled: bool
    autoAllowBashIfSandboxed: bool
    excludedCommands: list[str]
    allowUnsandboxedCommands: bool
    network: SandboxNetworkConfig
    ignoreViolations: SandboxIgnoreViolations
    enableWeakerNestedSandbox: bool
PropertiTipeDefaultDeskripsi
enabledboolFalseAktifkan mode sandbox untuk eksekusi perintah
autoAllowBashIfSandboxedboolTruePersetujuan otomatis perintah bash ketika sandbox diaktifkan
excludedCommandslist[str][]Perintah yang selalu melewati pembatasan sandbox (misalnya, ["docker"]). Ini berjalan tanpa sandbox secara otomatis tanpa keterlibatan model
allowUnsandboxedCommandsboolTrueIzinkan model untuk meminta menjalankan perintah di luar sandbox. Ketika True, model dapat mengatur dangerouslyDisableSandbox dalam input tool, yang jatuh kembali ke sistem izin
networkSandboxNetworkConfigNoneKonfigurasi sandbox spesifik jaringan
ignoreViolationsSandboxIgnoreViolationsNoneKonfigurasi pelanggaran sandbox mana yang akan diabaikan
enableWeakerNestedSandboxboolFalseAktifkan sandbox bersarang yang lebih lemah untuk kompatibilitas
Sandbox bergantung pada dukungan platform dan, di Linux, alat seperti bubblewrap dan socat. Secara default, ketika enabled adalah True tetapi sandbox tidak dapat dimulai, perintah berjalan tanpa sandbox dengan peringatan di stderr. Default ini berbeda dari SDK TypeScript, di mana failIfUnavailable default ke true.Atur "failIfUnavailable": True dalam pengaturan sandbox Anda untuk berhenti sebagai gantinya. Kunci belum dideklarasikan pada SandboxSettings namun, tetapi SDK meneruskannya ke Claude Code, yang menghormatinya. query() kemudian melaporkan ResultMessage dengan subtype="error_during_execution" dan alasannya dalam errors. Perhatikan subtype itu daripada mengharapkan query() untuk menaikkan sebelum menghasilkan pesan.

Contoh penggunaan

from claude_agent_sdk import query, ClaudeAgentOptions, SandboxSettings

sandbox_settings: SandboxSettings = {
    "enabled": True,
    "autoAllowBashIfSandboxed": True,
    "network": {"allowLocalBinding": True},
}

async for message in query(
    prompt="Build and test my project",
    options=ClaudeAgentOptions(sandbox=sandbox_settings),
):
    print(message)
Keamanan Unix socket: Opsi allowUnixSockets dapat memberikan akses ke layanan sistem yang kuat. Misalnya, mengizinkan /var/run/docker.sock secara efektif memberikan akses sistem host penuh melalui API Docker, melewati isolasi sandbox. Hanya izinkan Unix sockets yang benar-benar diperlukan dan pahami implikasi keamanan dari masing-masing.

SandboxNetworkConfig

Konfigurasi spesifik jaringan untuk mode sandbox. Pengaturan ini berlaku untuk perintah Bash dalam sandbox ketika enabled adalah True dalam SandboxSettings induk. Mereka tidak membatasi tool WebFetch, yang menggunakan aturan izin sebagai gantinya.
class SandboxNetworkConfig(TypedDict, total=False):
    allowedDomains: list[str]
    deniedDomains: list[str]
    allowManagedDomainsOnly: bool
    allowUnixSockets: list[str]
    allowAllUnixSockets: bool
    allowLocalBinding: bool
    allowMachLookup: list[str]
    httpProxyPort: int
    socksProxyPort: int
PropertiTipeDefaultDeskripsi
allowedDomainslist[str][]Nama domain yang dapat diakses oleh proses dalam sandbox
deniedDomainslist[str][]Nama domain yang tidak dapat diakses oleh proses dalam sandbox. Mengambil prioritas atas allowedDomains
allowManagedDomainsOnlyboolFalseHanya pengaturan terkelola: ketika diatur dalam pengaturan terkelola, abaikan allowedDomains dari sumber pengaturan non-terkelola. Tidak berpengaruh ketika diatur melalui opsi SDK
allowUnixSocketslist[str][]Jalur Unix socket yang dapat diakses proses (misalnya, Docker socket)
allowAllUnixSocketsboolFalseIzinkan akses ke semua Unix socket
allowLocalBindingboolFalseIzinkan proses untuk mengikat ke port lokal (misalnya, untuk dev server)
allowMachLookuplist[str][]Hanya macOS: nama layanan XPC/Mach yang diizinkan. Mendukung wildcard di akhir
httpProxyPortintNonePort proxy HTTP untuk permintaan jaringan
socksProxyPortintNonePort proxy SOCKS untuk permintaan jaringan
Proxy sandbox bawaan memberlakukan daftar izin jaringan berdasarkan nama host yang diminta dan tidak menghentikan atau memeriksa lalu lintas TLS, sehingga teknik seperti domain fronting dapat berpotensi melewatinya. Lihat Batasan keamanan sandboxing untuk detail dan Penyebaran aman untuk mengonfigurasi proxy yang menghentikan TLS.

SandboxIgnoreViolations

Konfigurasi untuk mengabaikan pelanggaran sandbox tertentu.
class SandboxIgnoreViolations(TypedDict, total=False):
    file: list[str]
    network: list[str]
PropertiTipeDefaultDeskripsi
filelist[str][]Pola jalur file untuk mengabaikan pelanggaran
networklist[str][]Pola jaringan untuk mengabaikan pelanggaran

Fallback Izin untuk Perintah Tanpa Sandbox

Ketika allowUnsandboxedCommands diaktifkan, model dapat meminta untuk menjalankan perintah di luar sandbox dengan mengatur dangerouslyDisableSandbox: True dalam input tool. Permintaan ini jatuh kembali ke sistem izin yang ada, berarti handler can_use_tool Anda akan dipanggil, memungkinkan Anda menerapkan logika otorisasi kustom.
excludedCommands vs allowUnsandboxedCommands:
  • excludedCommands: Daftar statis perintah yang selalu melewati sandbox secara otomatis (misalnya, ["docker"]). Model tidak memiliki kontrol atas ini.
  • allowUnsandboxedCommands: Memungkinkan model memutuskan saat runtime apakah akan meminta eksekusi tanpa sandbox dengan mengatur dangerouslyDisableSandbox: True dalam input tool.
from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    HookMatcher,
    PermissionResultAllow,
    PermissionResultDeny,
    ToolPermissionContext,
)


async def can_use_tool(
    tool: str, input: dict, context: ToolPermissionContext
) -> PermissionResultAllow | PermissionResultDeny:
    # Check if the model is requesting to bypass the sandbox
    if tool == "Bash" and input.get("dangerouslyDisableSandbox"):
        # The model is requesting to run this command outside the sandbox
        print(f"Unsandboxed command requested: {input.get('command')}")

        if is_command_authorized(input.get("command")):
            return PermissionResultAllow()
        return PermissionResultDeny(
            message="Command not authorized for unsandboxed execution"
        )
    return PermissionResultAllow()


# Required: dummy hook keeps the stream open for can_use_tool
async def dummy_hook(input_data, tool_use_id, context):
    return {"continue_": True}


async def prompt_stream():
    yield {
        "type": "user",
        "message": {"role": "user", "content": "Deploy my application"},
    }


async def main():
    async for message in query(
        prompt=prompt_stream(),
        options=ClaudeAgentOptions(
            sandbox={
                "enabled": True,
                "allowUnsandboxedCommands": True,  # Model can request unsandboxed execution
            },
            permission_mode="default",
            can_use_tool=can_use_tool,
            hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[dummy_hook])]},
        ),
    ):
        print(message)
Pola ini memungkinkan Anda untuk:
  • Audit permintaan model: Catat ketika model meminta eksekusi tanpa sandbox
  • Implementasikan allowlist: Hanya izinkan perintah tertentu untuk berjalan tanpa sandbox
  • Tambahkan alur persetujuan: Memerlukan otorisasi eksplisit untuk operasi istimewa
Perintah yang berjalan dengan dangerouslyDisableSandbox: True memiliki akses sistem penuh. Pastikan handler can_use_tool Anda memvalidasi permintaan ini dengan hati-hati.Jika permission_mode diatur ke bypassPermissions dan allow_unsandboxed_commands diaktifkan, model dapat secara otonom menjalankan perintah di luar sandbox tanpa prompt persetujuan apa pun. Kombinasi ini secara efektif memungkinkan model untuk melarikan diri dari isolasi sandbox secara diam-diam.

Lihat juga