Skip to content

Python SDK Reference

Version Requirement: This document is for CodeBuddy Agent SDK v0.1.0 and above.

This document provides a complete API reference for the Python SDK. For quick start and usage examples, please refer to SDK Overview.

Table of Contents

Requirements

DependencyVersion Requirement
Python>= 3.10
CodeBuddy CLIInstalled

Async Runtime: The SDK is based on asyncio, all APIs are asynchronous.

Installation

Recommended to use uv for dependency management:

bash
uv add codebuddy-agent-sdk

Or using pip:

bash
pip install codebuddy-agent-sdk

Environment Variables

Variable NameDescriptionRequired
CODEBUDDY_CODE_PATHCodeBuddy CLI executable pathOptional

If not set, the SDK will look for CLI in the following order:

  1. Environment variable CODEBUDDY_CODE_PATH
  2. Built-in binary within SDK package
  3. Development environment monorepo path

Authentication Configuration

The SDK supports authentication using existing login credentials, API Key, or OAuth Client Credentials. See SDK Overview - Authentication Configuration for details.

Functions

query()

Main API entry point, creates a query and returns an async iterator of messages.

python
async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: CodeBuddyAgentOptions | None = None,
    transport: Transport | None = None,
) -> AsyncIterator[Message]:

Parameters:

ParameterTypeDescription
promptstr | AsyncIterable[dict]Query prompt or user message stream
optionsCodeBuddyAgentOptionsConfiguration options (optional)
transportTransportCustom transport layer (optional)

Returns: AsyncIterator[Message] - Async iterator of messages

Example:

python
from codebuddy_agent_sdk import query, AssistantMessage, TextBlock

async for message in query(prompt="What is 2+2?"):
    if isinstance(message, AssistantMessage):
        for block in message.content:
            if isinstance(block, TextBlock):
                print(block.text)

Client Class

CodeBuddySDKClient

Client class for bidirectional interactive conversations. Supports multi-turn dialogues, interruptions, and dynamic control.

python
class CodeBuddySDKClient:
    def __init__(
        self,
        options: CodeBuddyAgentOptions | None = None,
        transport: Transport | None = None,
    ): ...

Methods:

connect()

Connect to CodeBuddy.

python
async def connect(
    self,
    prompt: str | AsyncIterable[dict[str, Any]] | None = None
) -> None:

query()

Send user message.

python
async def query(
    self,
    prompt: str | AsyncIterable[dict[str, Any]],
    session_id: str = "default",
) -> None:

receive_response()

Receive messages until a ResultMessage is received.

python
async def receive_response(self) -> AsyncIterator[Message]:

receive_messages()

Receive all messages (does not auto-stop).

python
async def receive_messages(self) -> AsyncIterator[Message]:

disconnect()

Disconnect.

python
async def disconnect(self) -> None:

Context Manager Support:

python
async with CodeBuddySDKClient() as client:
    await client.query("Hello!")
    async for msg in client.receive_response():
        print(msg)

Unstable API

Warning: The following APIs are experimental and may change in future versions.

interrupt()

Send interrupt signal.

python
async def interrupt(self) -> None:

set_permission_mode()

Dynamically modify permission mode.

python
async def set_permission_mode(self, mode: str) -> None:

set_model()

Dynamically modify model.

python
async def set_model(self, model: str | None = None) -> None:

Types

CodeBuddyAgentOptions

Complete configuration options:

python
@dataclass
class CodeBuddyAgentOptions:
    allowed_tools: list[str] = field(default_factory=list)
    disallowed_tools: list[str] = field(default_factory=list)
    system_prompt: str | AppendSystemPrompt | None = None
    mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
    permission_mode: PermissionMode | None = None
    continue_conversation: bool = False
    resume: str | None = None
    max_turns: int | None = None
    model: str | None = None
    fallback_model: str | None = None
    cwd: str | Path | None = None
    codebuddy_code_path: str | Path | None = None
    env: dict[str, str] = field(default_factory=dict)
    extra_args: dict[str, str | None] = field(default_factory=dict)
    stderr: Callable[[str], None] | None = None
    hooks: dict[HookEvent, list[HookMatcher]] | None = None
    include_partial_messages: bool = False
    fork_session: bool = False
    agents: dict[str, AgentDefinition] | None = None
    setting_sources: list[SettingSource] | None = None
    can_use_tool: CanUseTool | None = None
FieldTypeDescription
allowed_toolslist[str]Tool whitelist to auto-allow
disallowed_toolslist[str]Tool blacklist to disallow
system_promptstr | AppendSystemPromptSystem prompt configuration
mcp_serversdict[str, McpServerConfig]MCP server configuration
permission_modePermissionModePermission mode
continue_conversationboolContinue recent session
resumestrSession ID to resume
max_turnsintMaximum conversation turns
modelstrSpecify model
fallback_modelstrFallback model
cwdstr | PathWorking directory
codebuddy_code_pathstr | PathCLI executable path
envdict[str, str]Environment variables
extra_argsdict[str, str | None]Extra CLI arguments
stderrCallable[[str], None]stderr callback
hooksdict[HookEvent, list[HookMatcher]]Hook configuration
include_partial_messagesboolInclude partial messages
fork_sessionboolFork session
agentsdict[str, AgentDefinition]Custom agents
setting_sourceslist[SettingSource]Setting sources
can_use_toolCanUseToolPermission callback function

PermissionMode

python
PermissionMode = Literal["default", "acceptEdits", "plan", "bypassPermissions"]
ValueDescription
"default"Default mode, all operations require confirmation
"acceptEdits"Auto-approve file edits
"plan"Planning mode, only allow reads
"bypassPermissions"Skip all permission checks

PermissionResult

python
PermissionResult = PermissionResultAllow | PermissionResultDeny

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

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

CanUseTool

python
CanUseTool = Callable[
    [str, dict[str, Any], CanUseToolOptions],
    Awaitable[PermissionResult],
]

@dataclass
class CanUseToolOptions:
    tool_use_id: str
    signal: Any | None = None
    agent_id: str | None = None
    suggestions: list[dict[str, Any]] | None = None
    blocked_path: str | None = None
    decision_reason: str | None = None

AgentDefinition

python
@dataclass
class AgentDefinition:
    description: str        # Agent description
    prompt: str             # System prompt
    tools: list[str] | None = None           # Allowed tools
    disallowed_tools: list[str] | None = None  # Disallowed tools
    model: str | None = None                 # Model to use

McpServerConfig

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

McpServerConfig = McpStdioServerConfig

HookEvent

python
HookEvent = (
    Literal["PreToolUse"]
    | Literal["PostToolUse"]
    | Literal["UserPromptSubmit"]
    | Literal["Stop"]
    | Literal["SubagentStop"]
    | Literal["PreCompact"]
)

HookMatcher

python
@dataclass
class HookMatcher:
    matcher: str | None = None      # Match pattern (supports regex)
    hooks: list[HookCallback] = field(default_factory=list)
    timeout: float | None = None    # Timeout in seconds

HookCallback

python
HookCallback = Callable[
    [Any, str | None, HookContext],
    Awaitable[HookJSONOutput],
]

class HookContext(TypedDict):
    signal: Any | None

class SyncHookJSONOutput(TypedDict):
    continue_: NotRequired[bool]
    suppressOutput: NotRequired[bool]
    stopReason: NotRequired[str]
    decision: NotRequired[Literal["block"]]
    reason: NotRequired[str]

SettingSource

Controls which filesystem locations the SDK loads configuration from.

python
SettingSource = Literal["user", "project", "local"]
ValueDescriptionLocation
"user"Global user settings~/.codebuddy/settings.json
"project"Project shared settings.codebuddy/settings.json
"local"Project local settings.codebuddy/settings.local.json

Default Behavior: When setting_sources is not specified, the SDK does not load any filesystem configuration. This provides a completely clean runtime environment.

python
# Default: no configuration loaded (clean environment)
async for msg in query(prompt="..."):
    pass

# Load project configuration
options = CodeBuddyAgentOptions(setting_sources=["project"])

# Load all configurations (similar to CLI behavior)
options = CodeBuddyAgentOptions(setting_sources=["user", "project", "local"])

AppendSystemPrompt

python
@dataclass
class AppendSystemPrompt:
    append: str  # Content to append to default system prompt

Message Types

Message

Union of all message types:

python
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | StreamEvent

SystemMessage

python
@dataclass
class SystemMessage:
    subtype: str
    data: dict[str, Any]

UserMessage

python
@dataclass
class UserMessage:
    content: str | list[ContentBlock]
    uuid: str | None = None
    parent_tool_use_id: str | None = None

AssistantMessage

python
@dataclass
class AssistantMessage:
    content: list[ContentBlock]
    model: str
    parent_tool_use_id: str | None = None
    error: str | None = None

ResultMessage

python
@dataclass
class ResultMessage:
    subtype: str
    duration_ms: int
    duration_api_ms: int
    is_error: bool
    num_turns: int
    session_id: str
    total_cost_usd: float | None = None
    usage: dict[str, Any] | None = None
    result: str | None = None

StreamEvent

python
@dataclass
class StreamEvent:
    uuid: str
    session_id: str
    event: dict[str, Any]
    parent_tool_use_id: str | None = None

ContentBlock

python
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock

@dataclass
class TextBlock:
    text: str

@dataclass
class ThinkingBlock:
    thinking: str
    signature: str

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

@dataclass
class ToolResultBlock:
    tool_use_id: str
    content: str | list[dict[str, Any]] | None = None
    is_error: bool | None = None

Input Types

AskUserQuestionInput

python
@dataclass
class AskUserQuestionInput:
    questions: list[AskUserQuestionQuestion]
    answers: dict[str, str] | None = None

AskUserQuestionQuestion

python
@dataclass
class AskUserQuestionQuestion:
    question: str     # Complete question text (should end with ?)
    header: str       # Short label (max 12 characters)
    options: list[AskUserQuestionOption]
    multi_select: bool  # Whether to allow multiple selections

AskUserQuestionOption

python
@dataclass
class AskUserQuestionOption:
    label: str        # Display text (1-5 words)
    description: str  # Option description

Errors

All exceptions inherit from CodeBuddySDKError.

CodeBuddySDKError

python
class CodeBuddySDKError(Exception):
    """Base exception for CodeBuddy SDK errors."""
    pass

CLIConnectionError

Thrown when connection to CLI fails or no connection is established.

python
class CLIConnectionError(CodeBuddySDKError):
    pass

CLINotFoundError

Thrown when CLI executable is not found.

python
class CLINotFoundError(CodeBuddySDKError):
    def __init__(
        self,
        message: str,
        platform: str | None = None,
        arch: str | None = None,
    ): ...

Attributes:

AttributeTypeDescription
platformstr | NoneCurrent platform
archstr | NoneCurrent architecture

CLIJSONDecodeError

Thrown when JSON decoding of CLI output fails.

python
class CLIJSONDecodeError(CodeBuddySDKError):
    pass

ProcessError

Thrown when CLI process encounters an error.

python
class ProcessError(CodeBuddySDKError):
    pass