Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.qoder.com/llms.txt

Use this file to discover all available pages before exploring further.

Functions

query()

The SDK’s main entry function. Creates an async iterator that streams messages in arrival order.
async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: QoderAgentOptions | None = None,
) -> AsyncIterator[Message]:
    ...

Parameters

ParameterTypeDescription
promptstr | AsyncIterable[dict[str, Any]]Pass a string for single-turn; pass an async iterable for multi-turn
optionsQoderAgentOptionsOptional session configuration

Return Value

Returns AsyncIterator[Message], consumed via async for.

QoderSDKClient

Class-based multi-turn conversation API. Suitable for scenarios that need to keep session state across turns or dynamically switch the model or permission mode.
client = QoderSDKClient(options=options)
await client.connect("Initial prompt.")
MethodDescription
client.query(prompt)Send a new round of user input
client.receive_response()Consume messages until ResultMessage
client.receive_messages()Background async iterator that receives the entire session message stream
client.connect(prompt) / client.disconnect()Manually manage the connection
client.interrupt()Interrupt the current generation or tool execution
client.set_model(model)Switch the model at runtime
client.set_permission_mode(mode)Switch the permission mode at runtime
client.stop_task(task_id)Stop a background task
client.apply_flag_settings(settings)Inject flag-level settings
client.supported_agents()List the agents currently available
client.get_mcp_status()Get the status of all MCP servers
client.set_mcp_servers(servers)Replace the MCP server configuration
client.reconnect_mcp_server(name)Reconnect a specific MCP server
client.toggle_mcp_server(name, enabled)Enable or disable an MCP server
client.get_available_models()Get the list of available models

Types

QoderAgentOptions

Configuration object for query() and QoderSDKClient. The Python SDK uses snake_case field names.
FieldTypeDefaultDescription
authInternalAuthOptions | dict | NoneNoneAuthentication configuration
on_auth_expiredCallable | NoneNoneCallback when authentication expires; triggered at most once per session
toolslist[str] | ToolsPreset | NoneNoneTool set. Pass a string array to restrict available tools; built-in tool names are listed in Built-in Tool List
allowed_toolslist[str][]Tool allowlist; listed tools are pre-authorized
disallowed_toolslist[str][]Tool blocklist; takes priority over allowed_tools and permission_mode
can_use_toolCanUseToolNoneCustom tool permission callback
permission_modePermissionModeNoneSession permission mode
allow_dangerously_skip_permissionsboolFalseAllow skipping permission checks; used together with permission_mode="bypassPermissions"
permission_prompt_tool_namestr | NoneNoneMCP tool name for permission prompts; mutually exclusive with can_use_tool
modelstr | NoneNoneModel to use
fallback_modelstr | NoneNoneFallback model when the main model fails
resolve_modelModelPolicyProviderNoneDynamic model-selection callback. Passing it switches into dynamic-callback mode; see Model Policy
resolve_model_timeout_msint500Callback timeout (milliseconds); only effective when resolve_model is passed
system_promptstr | SystemPromptPreset | SystemPromptFile | NoneNoneSystem prompt
cwdstr | Path | NoneNoneWorking directory
envdict[str, str | None]{}Environment variables passed to the CLI process
cli_pathstr | Path | NoneNonePath to the qodercli executable
session_idstr | NoneNoneSpecify the session UUID
resumestr | NoneNoneSession ID to resume
continue_conversationboolFalseContinue the most recent session
fork_sessionboolFalseWhen used with resume, fork into a new session ID
max_turnsint | NoneNoneMaximum conversation turns
include_partial_messagesboolFalseInclude StreamEvent streaming fragments; see Streaming Output
mcp_serversdict[str, McpServerConfig] | str | Path{}MCP server configuration; see MCP
allowed_mcp_server_nameslist[str][]Restrict which MCP servers are available
strict_mcp_configboolFalseStrict MCP validation
hooksdict[HookEvent, list[HookMatcher]] | NoneNoneLifecycle hooks; see Hooks
agentsdict[str, AgentDefinition] | NoneNoneProgrammatically defined subagents; see Agents Reference
agentstr | NoneNoneAgent name used by the main thread; see Agents Reference
settingsstr | Path | Settings | NoneNoneInline settings object or settings file path
setting_sourceslist[SettingSource] | NoneNoneWhich filesystem settings to load
add_dirslist[str | Path][]Additional directories accessible to the AI
extra_argsdict[str, str | None]{}Additional arguments passed to the CLI
pluginslist[SdkPluginConfig][]Load local plugins; see Plugins
skillslist[str] | Literal["all"] | NoneNoneEnabled skills; pass "all" to enable all
enable_file_checkpointingbool | NoneNoneEnable file checkpointing
thinkingThinkingConfig | NoneNoneThinking configuration

Authentication

from qoder_agent_sdk import access_token, access_token_from_env, qodercli_auth
Factory functionDescription
access_token(token)Pass the PAT directly
access_token_from_env()Read from the default environment variable QODER_PERSONAL_ACCESS_TOKEN
access_token_from_env("MY_PAT")Read from a specified environment variable
qodercli_auth()Reuse the local qodercli login session
For convenience usage, see SDK Authentication.

Agents Reference

This page summarizes the stable configuration items related to SDK Agents. For getting started and usage scenarios, see Subagent Usage Guide.

Sources of Available Agents

The agents available in the current session may come from multiple sources:
SourceDescription
SDK registrationRegistered for the current session via QoderAgentOptions.agents
CLI built-inBuilt-in Agents registered when qodercli starts
User / project configAgent definitions in the user or project configuration directory
PluginAgents provided by loaded plugins
In the interactive CLI, you can run /agents to view the currently discovered Agents; on the command line, run qodercli agents list. In the Python SDK, after QoderSDKClient connects, call client.supported_agents() to get a summary of agents available in the current session.

QoderAgentOptions.agents

Type: dict[str, AgentDefinition] | None Registers custom Agents available in the current session. The dict key is the Agent name and the value is that Agent’s definition.
The Agent tool is required: Custom subagents require the main session to delegate through the built-in Agent tool, so allowed_tools must include the Agent tool.
from qoder_agent_sdk import AgentDefinition, QoderAgentOptions


options = QoderAgentOptions(
    allowed_tools=["Agent"],
    agents={
        "reviewer": AgentDefinition(
            description="Reviews code quality and reports actionable findings.",
            prompt="Review the requested code and report concrete issues.",
            tools=["Read", "Grep", "Glob"],
        ),
    },
)
After registration, the model can invoke these subagents through the built-in Agent tool. The main session must include Agent in its tool set to delegate work; allowed_tools=["Agent"] is the required pre-authorization form. If you use tools to narrow the main session’s available tools, include Agent there as well.

QoderAgentOptions.agent

Type: str | None Specifies which Agent identity the main session runs as. The value can be a name registered in agents, or a built-in / plugin Agent name discovered by the current CLI.
options = QoderAgentOptions(
    agents={
        "planner": AgentDefinition(
            description="Plans work before implementation.",
            prompt="Break work into steps, risks, and validation checks.",
            tools=["Read", "Grep", "Glob"],
        ),
    },
    agent="planner",
)
When set, the main session uses that Agent’s prompt, model, and tool restrictions. When omitted, the default main-session behavior is used.

AgentDefinition

Definition of a custom Agent. The Python SDK’s AgentDefinition is a dataclass whose field names use the protocol-style camelCase. The fields below are the stable capabilities currently covered and verified by the SDK.
from dataclasses import dataclass
from typing import Any, Literal


@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
    mcpServers: list[str | dict[str, Any]] | None = None
    initialPrompt: str | None = None
    maxTurns: int | None = None
    effort: Literal["low", "medium", "high", "max"] | None = None
    permissionMode: PermissionMode | None = None
FieldTypeRequiredDescription
descriptionstrYesAgent purpose description; the model uses it to decide when to invoke the Agent
promptstrYesAgent system prompt
toolslist[str] | NoneNoTool allowlist for this Agent
disallowedToolslist[str] | NoneNoTools excluded from this Agent’s tool set
modelstr | NoneNoModel override; "inherit" means inherit the main session model
mcpServerslist[str | dict[str, Any]] | NoneNoMCP server specs available to this Agent
skillslist[str] | NoneNoSkill names preloaded into the Agent context
initialPromptstr | NoneNoFirst user input automatically submitted when this Agent is used as the main session Agent
maxTurnsint | NoneNoMaximum API turns for the Agent
effort"low" | "medium" | "high" | "max" | NoneNoReasoning effort level
permissionModePermissionMode | NoneNoPermission mode for tool execution inside this Agent
The Python SDK serializes AgentDefinition into the initialize request via dataclasses.asdict(); qodercli then parses it according to the current Agent schema.

description

Describes what tasks the Agent is suitable for. It affects whether the model chooses this Agent.
description="Runs project tests, analyzes failing output, and suggests fixes."
Prefer a clear triggering scenario. Avoid broad descriptions such as Helpful assistant.

prompt

The Agent’s system prompt. Use it to define the role, constraints, and output format.
prompt="""You are a security reviewer.
Check for authentication bypass, authorization bugs, injection risks, and secret leaks.
Return findings sorted by severity."""

tools

Tool allowlist for the Agent. When set, the Agent can only use the listed tools.
tools=["Read", "Grep", "Glob"]
When tools is omitted, the subagent default tool set is used. A subagent’s tool set does not inherit trimming from the main session’s allowed_tools.

disallowedTools

Excludes specific tools from the Agent’s tool set.
disallowedTools=["Bash", "Write"]
When disallowedTools is omitted, the subagent does not inherit trimming from the main session’s disallowed_tools. Usually avoid setting both tools and disallowedTools unless you explicitly know the final tool set.

model

Specifies the model for the Agent; when omitted, the session default model is used. At the Python type level it is str | None; the SDK does not restrict specific strings locally. Common model tiers include:
ValueTierDescriptionSuitable forCredit cost
"auto"Smart routingIntelligently selects the best model, balancing capability and costMost daily development work; recommended default~1.0x
"ultimate"UltimateExpert-level deep reasoning and thinking capabilityComplex system design and difficult analysis~1.6x
"performance"PerformanceAdvanced reasoning and high-quality outputCore implementation, architecture design, refactoring~1.1x
"efficient"EfficientStandard reasoning with good cost efficiencyBasic code generation, unit tests, daily Q&A~0.3x
"lite"LiteBasic reasoning, free to useQuick validation, simple logic, quick questions0x
Agents also support two special forms:
ValueDescription
"inherit"Inherit the main session model; usually not echoed in supported_agents()
Full model IDDirectly specify a model ID supported by the current CLI / backend

mcpServers

mcpServers: list[str | dict[str, Any]] | None
Limits or adds MCP servers available to this Agent. Each entry can be a session-level server name, or an inline server configuration mapping. Reference a session-level MCP server:
options = QoderAgentOptions(
    mcp_servers={
        "orders": {
            "command": "python",
            "args": ["servers/orders.py"],
        },
    },
    allowed_tools=["Agent"],
    agents={
        "support": AgentDefinition(
            description="Answers support questions using order tools.",
            prompt="Use order tools when needed and return a concise answer.",
            mcpServers=["orders"],
            tools=["mcp__orders__lookup_order"],
        ),
    },
)
Configure a dedicated MCP server for a specific Agent:
AgentDefinition(
    description="Searches the internal knowledge base.",
    prompt="Search the knowledge base and cite relevant entries.",
    mcpServers=[
        {
            "kb": {
                "command": "python",
                "args": ["servers/kb.py"],
            },
        },
    ],
    tools=["mcp__kb__search"],
)
When you only want to expose a specific MCP tool, also configure tools=["mcp__server__tool"] to avoid exposing every tool of that server to the Agent.

skills

A list of skill names preloaded into the Agent context. Plain skill names and plugin-qualified names are both supported.
skills=["review", "sdk-test-plugin:sdk-echo"]
For session-level skill behavior, see Skills.

initialPrompt

Automatically submitted as the first user input when this Agent becomes the main session Agent through QoderAgentOptions.agent.
initialPrompt="Start by scanning authentication and session management code."
This field only takes effect for the main session Agent. It is ignored when the Agent is invoked as a subagent through the Agent tool.

maxTurns

Limits the Agent’s maximum API turns. Use it to control cost, execution time, and loop risk.
maxTurns=6

effort

EffortLevel = Literal["low", "medium", "high", "max"]
Controls the Agent’s reasoning effort level. Higher effort is usually suitable for complex reviews, architecture analysis, and high-risk changes, but increases latency and token usage.

permissionMode

Controls the permission mode for tool execution inside this Agent. It uses the same semantics as the session-level permission_mode, but its scope is limited to this Agent. For the session-level permission chain, the priority of allowed_tools / disallowed_tools / can_use_tool, and examples, see Permission Control.
PermissionMode = Literal[
    "default",
    "acceptEdits",
    "plan",
    "bypassPermissions",
    "yolo",
    "dontAsk",
    "auto",
]
ValueMeaningSuitable for
"default"Standard permission behavior. Tool calls still pass through tool sets, allow / deny rules, runtime approval, or CLI default policyMost interactive subagents
"acceptEdits"Automatically accepts file-edit operations; other sensitive operations still follow the permission flowA subagent that is approved to modify workspace files
"bypassPermissions"Skips permission checks. High-risk mode, usually only for trusted automation or test environmentsControlled CI, temporary validation, one-off automation
"yolo"Compatibility alias for "bypassPermissions"; also skips permission checksCompatibility with older configs; not recommended for new code
"plan"Plan mode. Suitable for producing a plan first; by default it does not perform real changesPlanning, design, review, or cases where the subagent should not modify files
"dontAsk"Does not ask interactively; operations that are not pre-authorized or allowed by rules are deniedNon-interactive environments, or workflows that should fail instead of prompting
"auto"Runtime capability decides allow or deny automaticallyReduce confirmation interruptions while retaining runtime judgment
For permission semantics, see Permission Control.

AgentInfo

Agent summary returned by QoderSDKClient.supported_agents().
class AgentInfo(TypedDict):
    name: str
    description: str
    model: NotRequired[str | None]
The Python SDK does not currently export a TypedDict named AgentInfo; the return type of supported_agents() is list[dict[str, Any]]. The structure above is the stable field convention of the actually returned dicts.
FieldTypeDescription
namestrAgent name
descriptionstrAgent purpose description
modelstr | NoneAgent model override; usually empty when unset or when model="inherit"
from qoder_agent_sdk import AgentDefinition, QoderAgentOptions, QoderSDKClient


options = QoderAgentOptions(
    agents={
        "reviewer": AgentDefinition(
            description="Reviews code quality.",
            prompt="Review code and report findings.",
        ),
    },
)

client = QoderSDKClient(options=options)
await client.connect("List agents.")
agents = client.supported_agents()
await client.disconnect()
The returned list may include Agents registered through agents, and may also include built-in, project, user, or plugin Agents discovered by the current CLI. The actual available entries depend on the qodercli version and current configuration.

Context and Invocation Boundaries

  • Subagents use independent context and do not receive the parent session’s full history.
  • The main information passed from the parent session to a subagent is the task prompt supplied to the Agent tool.
  • A subagent’s intermediate tool results do not directly enter the parent session; the parent session receives the subagent’s final response.
  • Subagents cannot spawn their own subagents, so do not put Agent in a subagent’s tools.
  • initialPrompt only takes effect for the main session Agent specified by agent.

Model Policy

Dynamic model-selection capability of query(). Two modes: fixed-model (no resolve_model, uses options.model or backend default) and dynamic-callback (pass resolve_model, the callback decides the model before every LLM call). For full concepts, triggers and error handling see Model Policy.

options.resolve_model

Type: ModelPolicyProvider Entry point for dynamic-callback mode. Once passed, dynamic-callback mode is enabled and the SDK calls this callback before every LLM request to fetch the model. The model returned by the callback is the final model for that request; there is no automatic fallback.

options.resolve_model_timeout_ms

Type: int, default 500 Callback timeout (milliseconds). On timeout ModelPolicyTimeoutError is thrown and the query fails (no fallback). Only effective when resolve_model is passed.

ModelPolicyProvider

Callback function signature. May be synchronous or asynchronous.
from typing import Awaitable, Callable

ModelPolicyProvider = Callable[
    ["ModelPolicyContext"],
    "ModelPolicyResult | Awaitable[ModelPolicyResult]",
]
Triggering scenarios are distinguished by QoderModelPurpose:
ScenariopurposeNotes
Main conversation'main'Re-invoked between turns / tools — a session may trigger many times
Subagent'subagent'Subagents share the same provider
WebFetch tool'web_fetch'After WebFetch retrieves content, a second LLM call summarizes it
ImageGen tool'image_gen'Used to pick the image-generation model
Context compaction'compact'Before compaction starts, the callback is queried for the compaction model
BYOKanySet model to a CustomModel object to route via a third-party LLM
Behavioral notes:
  • The callback may be triggered many times within a single session (re-invoked before every turn / tool / sub-task).
  • The model returned by the callback is the final model for that request; the SDK does not re-validate it.
  • Throwing an exception or returning an empty model fails the query directly. See Model Policy — Error handling.

ModelPolicyContext

The context passed to the callback on every invocation.
class ModelPolicyContext(TypedDict, total=False):
    purpose: str  # QoderModelPurpose
    sessionId: str
    agentId: str
    turnIndex: int
    availableModels: list[ModelInfo]
FieldTypeRequiredDescription
purposeQoderModelPurposeYesPurpose of this LLM call
sessionIdstrYesCurrent session ID; the same value is passed across callback invocations within a session, so it can be used as a cache / telemetry key
agentIdstrYesIdentifier of the Agent that initiated the call
turnIndexintYesCurrent turn index
availableModelsModelInfo[]YesThe models currently available to the account in real time (the CLI carries the list with every get_model_policy request)

QoderModelPurpose

from typing import Literal

QoderModelPurpose = Literal[
    "main",
    "plan",
    "task",
    "compact",
    "title",
    "suggestion",
    "generate",
    "hook_prompt",
    "subagent",
    "web_fetch",
    "image_gen",
    "compression",
    "utility",
]
ValueTriggering scenario
'main'Main-conversation LLM call
'subagent'Subagent call
'web_fetch'Secondary LLM call triggered by the WebFetch tool
'image_gen'Image-generation call triggered by the ImageGen tool
'compact'Context compaction / summarization

ModelPolicyResult

The callback’s return value.
class ModelPolicyResult(TypedDict, total=False):
    model: str | CustomModel
    parameters: dict[str, Any]
FieldTypeRequiredDescription
modelstr | CustomModelYesString: model identifier; object: BYOK credentials + model identifier
parametersdict[str, Any]NoModel-parameter overrides (e.g. temperature, max_tokens)
model forms:
  • String — any model ID supported by the backend (such as auto / performance / glm51); the exact set of valid values is returned in real time by client.get_available_models(). Must be non-empty, otherwise the query fails.
  • CustomModel object (BYOK) — the SDK extracts the object’s model field as the model identifier for this call, and forwards the remaining fields as credentials to the CLI for routing to a third-party LLM.

CustomModel

BYOK credentials. In the resolve_model callback, set the model field directly to this object, and that LLM request will be routed to a third-party provider.
class CustomModel(TypedDict, total=False):
    provider: str
    model: str
    api_key: str
    url: str
    style: str  # "openai" | "anthropic"
FieldTypeRequiredDescription
providerstrYesProvider key — must match a BYOKProviderInfo.key
modelstrYesModel identifier — extracted by the SDK as the model ID for this call
api_keystrYesThe API Key supplied by the user
urlstrNoOverride the default base URL
stylestrNoUpstream protocol style, e.g. "openai" / "anthropic"; defaults to "openai"
Notes:
  • provider must match a key in the catalog, otherwise backend authentication fails.
  • A wrong api_key causes authentication to fail, which fails the query directly (dynamic-callback mode does not fall back).
  • BYOK calls report total_cost_usd as 0 on the platform; token usage is reported as-is and billed by the provider side.

BYOK Catalog Types

The provider/model catalog returned by client.list_byok_providers().
class SDKControlGetByokConfigResponse(TypedDict, total=False):
    providers: list[BYOKProviderInfo]


class BYOKProviderInfo(TypedDict, total=False):
    key: str
    display_name: str
    api_key_url: str
    url: str
    fields: list[BYOKFieldInfo]
    types: list[BYOKModelTypeInfo]


class BYOKFieldInfo(TypedDict, total=False):
    key: str
    display_name: str
    type: str  # e.g. "free_input"
    mandatory: bool


class BYOKModelTypeInfo(TypedDict, total=False):
    key: str
    display_name: str
    models: list[BYOKModelInfo]


class BYOKModelInfo(TypedDict, total=False):
    key: str
    display_name: str
    is_vl: bool
    is_reasoning: bool
    format: str
    max_input_tokens: int

BYOKProviderInfo

FieldTypeDescription
keystrProvider key — fill into CustomModel.provider for BYOK
display_namestrDisplay name
api_key_urlstrURL pointing the user where to obtain an API Key
urlstrBase URL for inference requests
fieldslist[BYOKFieldInfo]List of fields the provider requires the user to fill in
typeslist[BYOKModelTypeInfo]Model groups under this provider

BYOKFieldInfo

FieldTypeDescription
keystrField key (e.g. api_key)
display_namestrDisplay name shown to the user
typestrField type (e.g. "free_input")
mandatoryboolWhether the field is required

BYOKModelTypeInfo

FieldTypeDescription
keystrGroup key, common values: cp / tp / pg (optional)
display_namestrGroup display name
modelslist[BYOKModelInfo]Models within the group

BYOKModelInfo

FieldTypeDescription
keystrModel ID — fill into CustomModel.model
display_namestrDisplay name
is_vlboolWhether vision / multi-modal input is supported
is_reasoningboolWhether this is a reasoning model
formatstrUpstream protocol format (e.g. openai)
max_input_tokensintMaximum input token count

ModelInfo

Summary of an available model returned by client.get_available_models(). Also used as the element type of ModelPolicyContext.availableModels.
class ModelInfo(TypedDict, total=False):
    value: str
    displayName: str
    isEnabled: bool
FieldTypeDescription
valuestrModel identifier; usable as ModelPolicyResult.model or as the argument of client.set_model()
displayNamestrDisplay name
isEnabledbool | undefinedWhether currently available; undefined is treated as available

ModelPolicyTimeoutError

class ModelPolicyTimeoutError(Exception): ...
Thrown by the SDK when the resolve_model callback exceeds options.resolve_model_timeout_ms without returning. The query fails directly, with no fallback.

client.set_model()

async def set_model(self, model: str | None = None) -> None: ...
Switches the model in fixed-model mode at runtime. Takes effect on the next LLM call. Effective only in fixed-model mode; in dynamic-callback mode, calling it does not override the callback’s result. Valid model IDs: see ModelInfo.value.

client.get_available_models()

async def get_available_models(self) -> list[ModelInfo]: ...
Fetches the latest model list available to the current account in real time. Always returns the latest result, no caching; returns an empty array (does not throw) when the list cannot be fetched temporarily. In dynamic-callback mode, ModelPolicyContext.availableModels already carries the same up-to-date list, so calling this method explicitly is unnecessary.

client.list_byok_providers()

async def list_byok_providers(self) -> list[BYOKProviderInfo] | None: ...
Returns the BYOK provider/model catalog available to the current account as an array:
  • Returns None: the CLI does not support this API (graceful fallback, no exception).
  • Returns an array (may be empty): the list of providers available to the current account (an empty array means the account has not enabled BYOK).
For field semantics, see BYOK Catalog Types.

CanUseTool

Host-defined custom tool permission approval callback.
from collections.abc import Awaitable, Callable
from typing import Any


CanUseTool = Callable[
    [str, dict[str, Any], ToolPermissionContext],
    Awaitable[PermissionResult],
]

ToolPermissionContext

import asyncio
from dataclasses import dataclass, field
from typing import Any


@dataclass
class ToolPermissionContext:
    signal: asyncio.Event | None = None
    suggestions: list[Any] = field(default_factory=list)
    blocked_path: str | None = None
    decision_reason: str | None = None
    decision_reason_type: str | None = None
    classifier_approvable: bool | None = None
    title: str | None = None
    display_name: str | None = None
    description: str | None = None
    tool_use_id: str | None = None
    agent_id: str | None = None
    exit_plan_mode: ExitPlanModeApprovalDetails | None = None
FieldTypeDescription
signalasyncio.Event | NoneSet when cancelled
suggestionslist[Any]Permission update suggestions from the CLI
blocked_pathstr | NoneFile path triggering authorization (file-related scenarios only)
decision_reasonstr | NoneHuman-readable authorization reason from the CLI
decision_reason_typestr | NonePermission reason classification
classifier_approvablebool | NoneWhether the current call can be auto-approved by the runtime classifier
title / display_name / descriptionstr | NoneHuman-readable authorization text generated at runtime
tool_use_idstr | NoneThis tool invocation’s ID
agent_idstr | NoneSubagent ID initiating the call
exit_plan_modeExitPlanModeApprovalDetails | NoneApproval details when exiting plan mode
For full usage and examples, see Permission Control.

PermissionMode

PermissionMode = Literal[
    "default",
    "acceptEdits",
    "bypassPermissions",
    "yolo",
    "plan",
    "dontAsk",
    "auto",
]
ValueMeaningSuitable for
"default"Standard permission behavior. Tool calls are handled by tools, allow / deny rules, dynamic approval, or runtime policyMost interactive sessions
"acceptEdits"Automatically accepts file-edit operations; other sensitive operations still follow the permission flowSessions that are approved to modify the workspace
"bypassPermissions"Skips permission checks; must also set allow_dangerously_skip_permissions=TrueTrusted automation or test environments
"yolo"Compatibility alias for "bypassPermissions"; must also set allow_dangerously_skip_permissions=TrueCompatibility with older configs; not recommended for new code
"plan"Plan mode. Suitable for producing a plan first; by default it does not perform real changesPlanning, design, review
"dontAsk"Does not ask interactively; operations that are not pre-authorized or allowed by rules are deniedNon-interactive environments, or workflows that should fail instead of prompting
"auto"Runtime capability decides allow or deny automatically; safe workspace file edits may be auto-allowedReduce confirmation interruptions while retaining runtime judgment
For more details on the permission chain, see Permission Control.

PermissionResult

Return value of CanUseTool.
from dataclasses import dataclass
from typing import Any, Literal


@dataclass
class PermissionResultAllow:
    behavior: Literal["allow"] = "allow"
    updated_input: dict[str, Any] | None = None
    updated_permissions: list[PermissionUpdate | dict[str, Any]] | None = None
    decision_classification: PermissionDecisionClassification | None = None


@dataclass
class PermissionResultDeny:
    behavior: Literal["deny"] = "deny"
    message: str = ""
    interrupt: bool = False
    decision_classification: PermissionDecisionClassification | None = None


PermissionResult = PermissionResultAllow | PermissionResultDeny
allow.updated_input, when modified, replaces the actual parameters the tool receives. deny.interrupt=True denies and also interrupts the Agent. The tool_name received by can_use_tool is the full tool name, for example "Bash", "Read", "mcp__orders__lookup_order".

McpServerConfig

MCP server configuration, passed to QoderAgentOptions.mcp_servers.
McpServerConfig = (
    McpStdioServerConfig
    | McpSSEServerConfig
    | McpHttpServerConfig
    | McpSdkServerConfig
)

McpStdioServerConfig

class McpStdioServerConfig(TypedDict):
    type: NotRequired[Literal["stdio"]]
    command: str
    args: NotRequired[list[str]]
    env: NotRequired[dict[str, str]]
    tools: NotRequired[list[McpServerToolPolicy]]

McpSSEServerConfig

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

McpHttpServerConfig

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

McpSdkServerConfig

class McpSdkServerConfig(TypedDict):
    type: Literal["sdk"]
    name: str
    instance: McpServer
    tools: NotRequired[list[McpServerToolPolicy]]
Returned by the create_sdk_mcp_server() factory; see MCP - In-Process Server.

McpServerToolPolicy

class McpServerToolPolicy(TypedDict):
    name: str
    permission_policy: Literal["always_allow", "always_ask", "always_deny"]

SdkPluginConfig

Load local plugins.
class SdkPluginConfig(TypedDict):
    type: Literal["local"]
    path: str
FieldTypeDescription
type"local"Currently only local is supported
pathstrAbsolute or relative path to the plugin directory

SettingSource

Controls which filesystem settings are loaded.
SettingSource = Literal["user", "project", "local"]
ValueMeaningLocation
"user"User-level global settings~/.qoder/settings.json
"project"Project shared settings (version controlled).qoder/settings.json
"local"Project local settings (gitignored).qoder/settings.local.json
When omitted, all sources are loaded per CLI defaults; pass [] to skip entirely.

Tools Reference

This page summarizes the stable tool-related APIs, the built-in tool list, and type definitions. For usage paths and scenarios, see Tools Usage Guide.
Note: The Python SDK currently does not export the built-in tool input / output type collections from the TypeScript SDK, such as BashInput, FileReadInput, or ToolInputSchemas. The implementation status is explicitly noted in the relevant sections.

ToolConfig

The TypeScript SDK provides options.toolConfig to configure the behavior of certain built-in tools:
type ToolConfig = {
  askUserQuestion?: {
    previewFormat?: "markdown" | "html";
  };
};
The Python SDK does not currently export an equivalent QoderAgentOptions.tool_config field; AskUserQuestion can still be used as a runtime tool name in tools, allowed_tools, disallowed_tools, can_use_tool, and hook matchers.

Built-in Tool List

In tools, allowed_tools, disallowed_tools, can_use_tool, hook matchers, and Agent tool allowlists, built-in tools use the runtime tool names in the table below.
CategoryTool nameDescriptionPython SDK status
Command executionBashExecute shell commandsUsable in permission / tool-scope configuration
File operationsReadRead file contentsUsable in permission / tool-scope configuration
File operationsEditEdit files by string matchingUsable in permission / tool-scope configuration
File operationsWriteCreate or overwrite filesUsable in permission / tool-scope configuration
SearchGlobSearch by filename patternUsable in permission / tool-scope configuration
SearchGrepSearch by content regexUsable in permission / tool-scope configuration
NetworkWebFetchFetch and process URL contentUsable in permission / tool-scope configuration
NetworkWebSearchWeb searchUsable in permission / tool-scope configuration
AgentAgentInvoke a subagentUsable in permission / tool-scope configuration
InteractionAskUserQuestionAsk the user a questionUsable in permission / tool-scope configuration
NotebookNotebookEditEdit notebook cellsUsable in permission / tool-scope configuration
Background tasksTaskOutputSend output to a background taskUsable in permission / tool-scope configuration
Background tasksTaskStopStop a background taskUsable in permission / tool-scope configuration
Plan / worktreeExitPlanModeExit plan modeUsable in permission / tool-scope configuration
Plan / worktreeEnterWorktreeEnter a git worktreeUsable in permission / tool-scope configuration
Plan / worktreeExitWorktreeExit a worktreeUsable in permission / tool-scope configuration
ConfigConfigRead or write configurationUsable in permission / tool-scope configuration
TodoTodoWriteManage todo itemsUsable in permission / tool-scope configuration
MCP resourcesListMcpResourcesList MCP resourcesUsable in permission / tool-scope configuration
MCP resourcesReadMcpResourceRead an MCP resourceUsable in permission / tool-scope configuration
MCP invocationMcpGeneric MCP tool callUsable in permission / tool-scope configuration
Custom MCP tool names use this format:
mcp__{serverName}__{toolName}

tool()

Creates an SDK MCP tool definition. The Python version is decorator-style; the handler is wrapped via @tool(...).
from collections.abc import Awaitable, Callable
from typing import Any

from mcp.types import ToolAnnotations


def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any],
    annotations: ToolAnnotations | None = None,
) -> Callable[[Callable[..., Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]:
    ...
ParameterTypeRequiredSemanticsCurrent Qoder behavior
namestrYesUnique identifier of the tool within the current MCP serverForms the model-visible full tool name mcp__{serverName}__{name}; required to be non-empty at registration
descriptionstrYesTool description shown to the model — when to use it, what it does, what it returnsPassed through to the tool list and directly affects whether the model invokes it correctly; required to be non-empty at registration
input_schematype | dict[str, Any]YesDefines the tool’s input parametersThe SDK generates an MCP input schema; supports a simple dict, a TypedDict, or a complete JSON Schema dict
annotationsToolAnnotations | NoneNoAdditional tool metadataThe SDK registers annotations on the MCP server; does not replace permission configuration
tool() itself only defines the tool; the decorated async handler is the function executed when the tool is called. Registration constraints such as name, description, and duplicate tool names are validated by create_sdk_mcp_server() when the tool is registered.

input_schema

The Python SDK does not have the TypeScript SDK’s AnyZodRawShape / InferShape. The Python version of input_schema supports the following forms:
# Simple dict: all fields required
{"query": str, "limit": int}

# Use Annotated to add a field description
{"query": Annotated[str, "Search keywords"]}

# TypedDict: supports NotRequired
class SearchInput(TypedDict):
    query: str
    limit: NotRequired[int]

# Complete JSON Schema dict
{
    "type": "object",
    "properties": {
        "query": {"type": "string"},
        "source": {"type": "string", "enum": ["docs", "wiki"]},
    },
    "required": ["query"],
}
Common Python type conversions:
Python formJSON Schema semantics
str{"type": "string"}
int{"type": "integer"}
float{"type": "number"}
bool{"type": "boolean"}
list[T]array, with items
dictobject
Annotated[T, "..."]adds description to T’s schema
TypedDictobject; generates required based on required / NotRequired

TypeScript-only schema helper types

TypeScript reference typePython SDK statusPython equivalent capability
AnyZodRawShapeNot implemented / not exportedUse dict[str, type], TypedDict, or a complete JSON Schema dict
InferShapeNot implemented / not exportedThe handler receives an args dict; if static typing is needed, declare your own TypedDict in business code
ToolExtrasNot implemented / not exportedIn Python, annotations is passed directly as the 4th argument to @tool()

SdkMcpTool

from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import Any, Generic, TypeVar

from mcp.types import ToolAnnotations


T = TypeVar("T")


@dataclass
class SdkMcpTool(Generic[T]):
    name: str
    description: str
    input_schema: type[T] | dict[str, Any]
    handler: Callable[..., Awaitable[dict[str, Any]]]
    annotations: ToolAnnotations | None = None
The @tool() decorator returns an SdkMcpTool. You typically do not need to construct one manually.

ToolInvocationContext

import asyncio
from dataclasses import dataclass, field


@dataclass
class ToolInvocationContext:
    signal: asyncio.Event = field(default_factory=asyncio.Event)
The handler may take one or two parameters:
@tool("watch", "Watch a counter.", {"max": int})
async def watch(args, extra: ToolInvocationContext):
    ...
When the handler accepts a second positional parameter, the SDK passes a ToolInvocationContext. extra.signal is set when the CLI cancels an in-flight tool call.

ToolAnnotations

The Python version directly uses mcp.types.ToolAnnotations.
from mcp.types import ToolAnnotations


ToolAnnotations(
    title="Search docs",
    readOnlyHint=True,
    destructiveHint=False,
    idempotentHint=True,
    openWorldHint=False,
    maxResultSizeChars=500_000,
)
FieldTypeOptionalSemanticsCurrent Qoder behavior
titlestrYesHuman-readable title of the toolMCP metadata; not currently a verified Qoder behavior capability
readOnlyHintboolYesMarks the tool as not modifying stateThe observable effect today is that read-only tools are eligible for concurrent execution within the same batch of tool calls; not a permission switch
destructiveHintboolYesMarks the tool as potentially performing destructive updatesRisk metadata; does not currently auto-block authorized tool execution
openWorldHintboolYesMarks whether the tool interacts with an open external worldExternal-interaction metadata; does not currently auto-block authorized tool execution
maxResultSizeCharsintYesMarks the tool’s result-size capThe Python SDK writes it into _meta["anthropic/maxResultSizeChars"] for the CLI to read; this is the MCP type extension field currently used in Python
These fields are metadata and scheduling hints, not permission switches. Whether execution is allowed is still determined by tools, allowed_tools, disallowed_tools, permission_mode, can_use_tool, and hooks.

create_sdk_mcp_server()

Creates an MCP server that runs in the same process as the SDK.
from typing import Any


def create_sdk_mcp_server(
    name: str,
    version: str = "1.0.0",
    tools: list[SdkMcpTool[Any]] | None = None,
) -> McpSdkServerConfig:
    ...
ParameterDefaultDescription
nameRequiredMCP server name; used in mcp__{serverName}__{toolName}
version"1.0.0"Server version info
toolsNoneList of tools registered to this server

CreateSdkMcpServerOptions

The TypeScript SDK uses a CreateSdkMcpServerOptions object parameter; the Python SDK does not export this type and does not use an options object. The Python equivalent is the three function parameters of create_sdk_mcp_server(name, version="1.0.0", tools=None).

Return Value

Returns an McpSdkServerConfig that can be used directly as a value in QoderAgentOptions.mcp_servers.
from typing import Literal, TypedDict

from typing_extensions import NotRequired


class McpSdkServerConfig(TypedDict):
    type: Literal["sdk"]
    name: str
    instance: McpServer
    tools: NotRequired[list[McpServerToolPolicy]]

McpServerToolPolicy

class McpServerToolPolicy(TypedDict):
    name: str
    permission_policy: Literal["always_allow", "always_ask", "always_deny"]
The tools policy field exists in the Python types. It is primarily used for tool permission policy at the MCP server configuration layer; common in-process SDK server integrations are still controlled through allowed_tools, disallowed_tools, permission_mode, can_use_tool, and hooks.

CallToolResult

The Python SDK does not export its own CallToolResult type. Handlers return a dict, and the SDK converts it into the MCP CallToolResult.
from typing import Literal, TypedDict

from typing_extensions import NotRequired


class TextToolContent(TypedDict):
    type: Literal["text"]
    text: str


class ImageToolContent(TypedDict):
    type: Literal["image"]
    data: str
    mimeType: str


class ResourceLinkToolContent(TypedDict):
    type: Literal["resource_link"]
    uri: str
    name: NotRequired[str]
    description: NotRequired[str]
    mimeType: NotRequired[str]


class EmbeddedResourceValue(TypedDict, total=False):
    uri: str
    mimeType: str
    text: str
    blob: str


class EmbeddedResourceToolContent(TypedDict):
    type: Literal["resource"]
    resource: EmbeddedResourceValue


ToolContent = (
    TextToolContent
    | ImageToolContent
    | ResourceLinkToolContent
    | EmbeddedResourceToolContent
)


class ToolHandlerResult(TypedDict):
    content: list[ToolContent]
    is_error: NotRequired[bool]

McpToolResultContent

The Python SDK currently recognizes the following content blocks:
TypePython handler dictCurrent Qoder behavior
Text{"type": "text", "text": "..."}Converted to TextContent
Image{"type": "image", "data": "...", "mimeType": "image/png"}Converted to ImageContent
Resource link{"type": "resource_link", "uri": "...", "name": "...", "description": "..."}Downgraded to TextContent, concatenating name / uri / description
Embedded text resource{"type": "resource", "resource": {"text": "..."}}Converted to TextContent
Embedded binary resource{"type": "resource", "resource": {"blob": "..."}}Currently skipped, with a warning logged
Differences from the TS reference:
  • The Python handler uses is_error, not the MCP / TypeScript isError field name; the SDK maps it to MCP isError internally.
  • Top-level _meta on the Python handler is not currently passed through to CallToolResult.
  • The Python call_tool conversion logic does not currently handle the audio content block; even though MCP types import AudioContent, a handler returning {"type": "audio"} will fall into the unsupported-content warning branch.

can_use_tool

The tool permission approval callback is defined in the common types and is repeated here for ease of reference.
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from typing import Any, Literal


@dataclass
class ToolPermissionContext:
    signal: asyncio.Event | None = None
    suggestions: list[Any] = field(default_factory=list)
    blocked_path: str | None = None
    decision_reason: str | None = None
    decision_reason_type: str | None = None
    classifier_approvable: bool | None = None
    title: str | None = None
    display_name: str | None = None
    description: str | None = None
    tool_use_id: str | None = None
    agent_id: str | None = None
    exit_plan_mode: ExitPlanModeApprovalDetails | None = None


CanUseTool = Callable[
    [str, dict[str, Any], ToolPermissionContext],
    Awaitable[PermissionResult],
]

PermissionResult

@dataclass
class PermissionResultAllow:
    behavior: Literal["allow"] = "allow"
    updated_input: dict[str, Any] | None = None
    updated_permissions: list[PermissionUpdate | dict[str, Any]] | None = None
    decision_classification: PermissionDecisionClassification | None = None


@dataclass
class PermissionResultDeny:
    behavior: Literal["deny"] = "deny"
    message: str = ""
    interrupt: bool = False
    decision_classification: PermissionDecisionClassification | None = None


PermissionResult = PermissionResultAllow | PermissionResultDeny
The tool_name received by can_use_tool is the full tool name, for example Bash, Read, mcp__orders__lookup_order.

MCP Status Tool Information

The Python SDK exports McpToolInfo and McpToolAnnotations to describe the per-server tool information returned by QoderSDKClient.get_mcp_status().
from typing import TypedDict

from typing_extensions import NotRequired


class McpToolAnnotations(TypedDict, total=False):
    readOnly: bool
    destructive: bool
    openWorld: bool


class McpToolInfo(TypedDict):
    name: str
    description: NotRequired[str]
    annotations: NotRequired[McpToolAnnotations]
Note: the annotation field names in status are the CLI-projected readOnly, destructive, openWorld, not the readOnlyHint, destructiveHint, openWorldHint from the ToolAnnotations input. idempotentHint is not currently echoed in the status tool list.

Built-in Tool Input/Output Types

The TypeScript SDK provides input / output structures for built-in tools at the type level. The Python SDK currently does not export these TypedDicts, nor does it export ToolInputSchemas / ToolOutputSchemas union types. Note: the type names in the table below are the TypeScript reference type names; Python permission configuration and tool allowlists still use the runtime tool names from Built-in Tool List.
TypeScript typePython SDK status
AgentInput / AgentOutputNot exported
BashInput / BashOutputNot exported
FileReadInput / FileReadOutputNot exported; runtime tool name remains Read
FileEditInput / FileEditOutputNot exported; runtime tool name remains Edit
FileWriteInput / FileWriteOutputNot exported; runtime tool name remains Write
GlobInput / GlobOutputNot exported
GrepInput / GrepOutputNot exported
WebFetchInput / WebFetchOutputNot exported
WebSearchInput / WebSearchOutputNot exported
AskUserQuestionInput / AskUserQuestionOutputNot exported
NotebookEditInput / NotebookEditOutputNot exported
TaskOutputInputNot exported
TaskStopInput / TaskStopOutputNot exported
ExitPlanModeInput / ExitPlanModeOutputNot exported
ConfigInput / ConfigOutputNot exported
EnterWorktreeInput / EnterWorktreeOutputNot exported
ExitWorktreeInput / ExitWorktreeOutputNot exported
TodoWriteInput / TodoWriteOutputNot exported
ListMcpResourcesInput / ListMcpResourcesOutputNot exported
ReadMcpResourceInputNot exported
McpInput / McpOutputNot exported
ToolInputSchemasNot exported
ToolOutputSchemasNot exported
What the Python side exposes as stable and configurable is the runtime tool names in Built-in Tool List. If you need strongly-typed built-in tool parameters in a Python application, define your own TypedDict or dataclass on the business side.

Hooks Reference

For usage guides and examples, see Hooks.

Event Overview

EventTriggerControllable behavior
PreToolUseBefore a tool callBlock / allow / modify input
PostToolUseAfter a tool succeedsAudit / inject context / override output
PostToolUseFailureAfter a tool failsError handling / logging
UserPromptSubmitBefore a user prompt is sentInject context / block
SessionStartWhen a session startsInitialize / inject context
SessionEndWhen a session endsCleanup / logging
StopWhen AI stops generatingBlock stop and force continuation
SubagentStartWhen a subagent startsObserve / log
SubagentStopWhen a subagent stopsObserve / log
PreCompactBefore context compactionObserve / log
PostCompactAfter context compactionObserve / log
CwdChangedWhen the working directory changesObserve / log
InstructionsLoadedWhen an instructions file is loadedObserve / log
FileChangedWhen a file is created/modified/deletedObserve / log
PermissionRequestWhen a permission is requestedAuto-approve / deny permission requests

HookEvent

Union type of registrable hook events.
HookEvent = Literal[
    "PreToolUse",
    "PostToolUse",
    "PostToolUseFailure",
    "UserPromptSubmit",
    "SessionStart",
    "SessionEnd",
    "Stop",
    "SubagentStart",
    "SubagentStop",
    "PreCompact",
    "PostCompact",
    "CwdChanged",
    "InstructionsLoaded",
    "FileChanged",
    "PermissionRequest",
]

HookCallback

HookCallback = Callable[
    [HookInput, str | None, HookCallbackOptions],
    Awaitable[HookJSONOutput],
]

HookMatcher

@dataclass
class HookMatcher:
    hooks: list[HookCallback]
    matcher: str | None = None
    timeout: int | None = None  # seconds, default 60
FieldTypeDescription
hookslist[HookCallback]List of callbacks executed when matched
matcherstr | NoneOptional regex; filters by tool_name
timeoutint | NoneOptional timeout (seconds); default 60

BaseHookInput

Common input fields for all hook events.
@dataclass
class BaseHookInput:
    hook_event_name: str
    session_id: str
    transcript_path: str
    cwd: str
FieldTypeDescription
hook_event_namestrEvent-type identifier (e.g. "PreToolUse")
session_idstrUnique identifier of the current session
transcript_pathstrPath to the session transcript file (JSONL format)
cwdstrCurrent working directory of the session

HookJSONOutput

Return type of a hook callback.
@dataclass
class HookJSONOutput:
    continue_: bool | None = None       # JSON key is "continue"
    stop_reason: str | None = None      # JSON key is "stopReason"
    decision: str | None = None
    reason: str | None = None
    hook_specific_output: dict | None = None  # JSON key is "hookSpecificOutput"
FieldTypeDefaultDescription
continue_bool | NoneNone (equivalent to True)Set to False to terminate the session. Effective only for PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, Stop, SubagentStop
stop_reasonstr | NoneNoneHuman-readable reason for stopping the session (used with continue_=False)
decisionstr | NoneNone"approve" or "block". "block" blocks tool execution; for the Stop event, "block" blocks stopping and forces continuation
reasonstr | NoneNoneReason for the decision (shown to the model; for the "block" decision on a Stop event, injected as a continuation prompt into the context)
hook_specific_outputdict | NoneNoneEvent-specific output (see each event type)
In the Python SDK, continue_ corresponds to the JSON key "continue" (to avoid the keyword conflict). When multiple hooks return conflicting decision values, "deny" / "block" takes priority (the strictest rule wins).

PreToolUseHookInput

@dataclass
class PreToolUseHookInput(BaseHookInput):
    hook_event_name: Literal["PreToolUse"]
    permission_mode: str | None
    tool_name: str
    tool_input: Any
FieldTypeDescription
permission_modestr | NoneCurrent permission mode of the session
tool_namestrName of the tool being invoked
tool_inputAnyParameters passed to the tool
hook_specific_output (hookSpecificOutput):
FieldTypeDescription
hookEventName"PreToolUse"Must be set
permissionDecisionstr"allow" / "deny" / "ask" / "defer"
permissionDecisionReasonstrReason for the permission decision
updatedInputdictModified tool input that replaces the original tool_input
additionalContextstrExtra context injected into the model’s next turn

PostToolUseHookInput

@dataclass
class PostToolUseHookInput(BaseHookInput):
    hook_event_name: Literal["PostToolUse"]
    tool_name: str
    tool_input: Any
    tool_response: Any
FieldTypeDescription
tool_namestrName of the tool being invoked
tool_inputAnyParameters passed to the tool
tool_responseAnyResult of tool execution
Output behavior:
FieldLocationBehavior
hookSpecificOutput.updatedToolOutputEvent-specific outputOverrides tool_response; the model only sees the overridden value
hookSpecificOutput.additionalContextEvent-specific outputAppends supplemental context without modifying the original result
decision: "block" + reasonTop-level outputPrevents the agent from further processing the tool result
hook_specific_output (hookSpecificOutput):
FieldTypeDescription
hookEventName"PostToolUse"Must be set
updatedToolOutputstrOverride the tool response content
additionalContextstrExtra context appended alongside the tool result
When multiple hooks set updatedToolOutput, the last non-empty value wins. For chained transformations, perform them sequentially within a single callback.

PostToolUseFailureHookInput

@dataclass
class PostToolUseFailureHookInput(BaseHookInput):
    hook_event_name: Literal["PostToolUseFailure"]
    tool_name: str
    tool_input: Any
    error: str
    is_interrupt: bool | None
FieldTypeDescription
tool_namestrName of the failed tool
tool_inputAnyParameters passed to the tool
errorstrError message
is_interruptbool | NoneWhether caused by an interrupt/abort

UserPromptSubmitHookInput

@dataclass
class UserPromptSubmitHookInput(BaseHookInput):
    hook_event_name: Literal["UserPromptSubmit"]
    prompt: str
FieldTypeDescription
promptstrText entered by the user
hook_specific_output (hookSpecificOutput):
FieldTypeDescription
hookEventName"UserPromptSubmit"Must be set
additionalContextstrExtra context appended to the user prompt

SessionStartHookInput

@dataclass
class SessionStartHookInput(BaseHookInput):
    hook_event_name: Literal["SessionStart"]
    source: str
FieldTypeDescription
sourcestrReason for starting the session: "startup" / "resume" / "clear" / "compact"
hook_specific_output (hookSpecificOutput):
FieldTypeDescription
hookEventName"SessionStart"Must be set
additionalContextstrContext injected at the start of the session

SessionEndHookInput

@dataclass
class SessionEndHookInput(BaseHookInput):
    hook_event_name: Literal["SessionEnd"]
    reason: str
FieldTypeDescription
reasonstrReason the session ended: "clear" / "resume" / "logout" / "prompt_input_exit" / "other" / "bypass_permissions_disabled"

StopHookInput

@dataclass
class StopHookInput(BaseHookInput):
    hook_event_name: Literal["Stop"]
    stop_hook_active: bool
FieldTypeDescription
stop_hook_activeboolWhether a Stop hook is currently blocking stopping
Returning {"decision": "block", "reason": "..."} blocks the AI from stopping and forces continuation. reason is injected into the model context as a continuation prompt.

SubagentStartHookInput

@dataclass
class SubagentStartHookInput(BaseHookInput):
    hook_event_name: Literal["SubagentStart"]
    agent_id: str
    agent_type: str
FieldTypeDescription
agent_idstrUnique identifier of the subagent instance
agent_typestrType / role of the subagent

SubagentStopHookInput

@dataclass
class SubagentStopHookInput(BaseHookInput):
    hook_event_name: Literal["SubagentStop"]
    stop_hook_active: bool
FieldTypeDescription
stop_hook_activeboolWhether a Stop hook is currently blocking stopping

PreCompactHookInput

@dataclass
class PreCompactHookInput(BaseHookInput):
    hook_event_name: Literal["PreCompact"]
    trigger: str
    custom_instructions: str | None
FieldTypeDescription
triggerstrTrigger reason: "manual" / "auto"
custom_instructionsstr | NoneCustom instructions for the compaction summary

PostCompactHookInput

@dataclass
class PostCompactHookInput(BaseHookInput):
    hook_event_name: Literal["PostCompact"]
    trigger: str
    compact_summary: str
FieldTypeDescription
triggerstrTrigger reason: "manual" / "auto"
compact_summarystrSummary generated after context compaction

CwdChangedHookInput

@dataclass
class CwdChangedHookInput(BaseHookInput):
    hook_event_name: Literal["CwdChanged"]
    old_cwd: str
    new_cwd: str
FieldTypeDescription
old_cwdstrWorking directory before the change
new_cwdstrWorking directory after the change

InstructionsLoadedHookInput

@dataclass
class InstructionsLoadedHookInput(BaseHookInput):
    hook_event_name: Literal["InstructionsLoaded"]
    load_reason: str
FieldTypeDescription
load_reasonstrLoad reason: "nested_traversal" / "path_glob_match"

FileChangedHookInput

@dataclass
class FileChangedHookInput(BaseHookInput):
    hook_event_name: Literal["FileChanged"]
    file_path: str
    event: str
FieldTypeDescription
file_pathstrPath of the changed file
eventstrFilesystem event: "change" / "add" / "unlink"

PermissionRequestHookInput

@dataclass
class PermissionRequestHookInput(BaseHookInput):
    hook_event_name: Literal["PermissionRequest"]
    tool_name: str
    tool_input: Any
    permission_suggestions: list | None
FieldTypeDescription
tool_namestrTool requesting permission
tool_inputAnyTool input parameters
permission_suggestionslist | NoneSuggested permission rules
hook_specific_output (hookSpecificOutput):
FieldTypeDescription
hookEventName"PermissionRequest"Must be set
decisiondictPermission decision (see below)
decision is one of:
  • Approve: {"behavior": "allow", "updatedInput": {...}, "updatedPermissions": [...]}
  • Deny: {"behavior": "deny", "message": "..."}

Message Types

AssistantMessage

The complete AI reply, delivered once per turn. content is a list of TextBlock and ToolUseBlock.
@dataclass
class AssistantMessage:
    content: list[TextBlock | ToolUseBlock]
    parent_tool_use_id: str | None = None
    session_id: str | None = None
    uuid: str | None = None

ResultMessage

The final message at the end of the entire session.
@dataclass
class ResultMessage:
    subtype: str  # "success" | "error_max_turns" | "error_during_execution" | ...
    duration_ms: int
    num_turns: int
    session_id: str
    total_cost_usd: float | None = None
    result: str | None = None  # only present when subtype == "success"

SystemMessage

Session system message. When subtype == "init", data carries initialization information (session_id, model, tools, etc.).
@dataclass
class SystemMessage:
    subtype: str  # "init" | "compact_boundary" | "status" | "mcp_status_change" | ...
    data: dict[str, Any]

StreamEvent

Requires include_partial_messages=True; streamed token-by-token.
@dataclass
class StreamEvent:
    uuid: str
    session_id: str
    event: dict[str, Any]  # upstream-compatible raw stream event
    parent_tool_use_id: str | None = None
event["type"] values:
event["type"]Description
message_startMessage begins
content_block_startBlock starts (text / tool_use / thinking)
content_block_deltaIncrement: text_delta / input_json_delta / thinking_delta
content_block_stopBlock ends
message_deltaMessage-level state change (e.g. stop_reason)
message_stopComplete turn ends
For full usage, see Streaming Output.

Content Blocks

Elements in AssistantMessage.content:
@dataclass
class TextBlock:
    text: str


@dataclass
class ToolUseBlock:
    id: str
    name: str
    input: dict[str, Any]