Skip to main content

Open-source Agent SDK backed by OpenCode ACP (drop-in replacement for claude_agent_sdk)

Project description

OpenCode Agent SDK for Python

Python SDK for building agents backed by OpenCode. Drop-in replacement for claude_agent_sdk with support for any LLM provider (Anthropic, OpenAI, xAI, etc.).

Installation

pip install opencode-agent-sdk

Prerequisites:

  • Python 3.10+
  • An OpenCode server (opencode serve) or the opencode CLI installed locally

Quick Start

import asyncio
from opencode_agent_sdk import SDKClient, AgentOptions, AssistantMessage, TextBlock

async def main():
    client = SDKClient(options=AgentOptions(
        model="claude-haiku-4-5",
        server_url="http://localhost:54321",
    ))

    await client.connect()
    await client.query("What is 2 + 2?")

    async for message in client.receive_response():
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)

    await client.disconnect()

asyncio.run(main())

Why OpenCode Agent SDK?

  • Drop-in Replacement: Seamlessly switch from claude_agent_sdk by just changing your imports.

  • Open Source & Headless: Take full control of your agent infrastructure. No more proprietary black boxes.

  • Multi-Provider Support: Use any LLM (Anthropic, OpenAI, xAI, Google, Locall) via OpenCode's backend.

  • Native SSE Streaming: Real-time response streaming for a better user experience.

  • Advanced Control: Fine-grained tool permission hooks and MCP server support builtin.

  • HTTP mode — communicates with a running opencode serve instance over REST

  • Subprocess mode — spawns opencode acp locally over stdio JSON-RPC

HTTP Mode (recommended)

Start the server, then connect:

docker compose up -d   # starts opencode serve on port 54321
from opencode_agent_sdk import SDKClient, AgentOptions

client = SDKClient(options=AgentOptions(
    model="claude-haiku-4-5",
    server_url="http://localhost:54321",
    system_prompt="You are a helpful assistant",
))

await client.connect()
await client.query("Hello!")

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

await client.disconnect()

Subprocess Mode

When server_url is not set, the SDK spawns opencode acp as a child process:

client = SDKClient(options=AgentOptions(
    cwd="/path/to/project",
    model="claude-haiku-4-5",
))

Resuming Sessions

options = AgentOptions(
    resume="session-id-from-previous-run",
    server_url="http://localhost:54321",
)

AgentOptions

Field Type Default Description
cwd str "." Working directory
model str "" Model identifier (e.g. "claude-haiku-4-5")
provider_id str "anthropic" Provider identifier
system_prompt str "" System prompt for the LLM
server_url str "" OpenCode server URL; enables HTTP mode when set
mcp_servers dict {} MCP server configurations
allowed_tools list[str] [] Tools the agent is allowed to use
permission_mode str "" Permission mode for tool execution
hooks dict {} Hook matchers keyed by event type
max_turns int 100 Maximum conversation turns
resume str | None None Session ID to resume

Custom Tools (MCP Servers)

Define tools as Python functions and expose them as in-process MCP servers:

from opencode_agent_sdk import tool, create_sdk_mcp_server, SDKClient, AgentOptions

@tool("greet", "Greet a user", {"type": "object", "properties": {"name": {"type": "string"}}})
def greet_user(args):
    return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}

server = create_sdk_mcp_server("my-tools", tools=[greet_user])

client = SDKClient(options=AgentOptions(
    mcp_servers={"my-tools": server},
    allowed_tools=["mcp__my-tools__greet"],
    server_url="http://localhost:54321",
))

You can mix in-process SDK servers with external MCP servers:

options = AgentOptions(
    mcp_servers={
        "internal": sdk_server,          # In-process SDK server
        "external": {                    # External stdio server
            "command": "external-server",
            "args": ["--port", "8080"],
        },
    }
)

Hooks

Hooks let you intercept and control tool execution. They run deterministically at specific points in the agent loop.

from opencode_agent_sdk import SDKClient, AgentOptions, HookMatcher

async def check_bash_command(input_data, tool_use_id, context):
    tool_input = input_data["tool_input"]
    command = tool_input.get("command", "")

    if "rm -rf" in command:
        return {
            "hookSpecificOutput": {
                "hookEventName": "PreToolUse",
                "permissionDecision": "deny",
                "permissionDecisionReason": "Destructive command blocked",
            }
        }
    return {}

options = AgentOptions(
    allowed_tools=["Bash"],
    hooks={
        "PreToolUse": [
            HookMatcher(matcher="Bash", hooks=[check_bash_command]),
        ],
    },
    server_url="http://localhost:54321",
)

client = SDKClient(options=options)
await client.connect()
await client.query("Run: echo hello")

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

await client.disconnect()

Hook event types: "PreToolUse", "Stop"

Types

See src/opencode_agent_sdk/types.py for complete type definitions:

  • AssistantMessage — LLM response containing TextBlock and/or ToolUseBlock
  • ResultMessage — Final message with usage stats, cost, and session info
  • SystemMessage — Internal events (init, tool results, thoughts)
  • TextBlock — Text content from the LLM
  • ToolUseBlock — Tool invocation with name and input
  • HookMatcher — Matches tool names to hook functions

Error Handling

from opencode_agent_sdk._errors import ProcessError

try:
    await client.connect()
except ProcessError as e:
    print(f"Failed with exit code: {e.exit_code}")

Migrating from claude_agent_sdk

This SDK mirrors the claude_agent_sdk API. Migration requires renaming imports:

# Before (claude_agent_sdk)
from claude_agent_sdk import (
    ClaudeAgentOptions, ClaudeSDKClient, AssistantMessage,
    ResultMessage, SystemMessage, TextBlock, ToolUseBlock, HookMatcher,
)
from claude_agent_sdk._errors import ProcessError

# After (opencode_agent_sdk)
from opencode_agent_sdk import (
    AgentOptions, SDKClient, AssistantMessage,
    ResultMessage, SystemMessage, TextBlock, ToolUseBlock, HookMatcher,
)
from opencode_agent_sdk._errors import ProcessError

All method calls, message types, hooks, and tool decorators stay the same. Only the class names change:

claude_agent_sdk opencode_agent_sdk
ClaudeSDKClient SDKClient
ClaudeAgentOptions AgentOptions

Demo: End-to-End Walkthrough

A full working demo that connects to opencode serve, sends a prompt to clone a GitHub repo, and streams the LLM response back through the SDK.

1. Configure API keys

Create a .env file in the project root with your provider key:

ANTHROPIC_API_KEY=sk-ant-...

2. Start the server

docker compose up -d opencode

This builds and starts the opencode serve container on port 54321.

3. Install dependencies

uv sync

4. Run the E2E demo

uv run python scripts/e2e_test.py

Expected output

============================================================
E2E Test: Clone repo & explain project
============================================================
Server: http://127.0.0.1:54321

[*] Connecting ...
[*] Connected.

[>] Prompt:
Clone the repo https://github.com/dingkwang/opencode-agent-sdk-python and then
explain what the project does. Give a concise summary of its purpose,
architecture, and key components.

------------------------------------------------------------

  [system:init]
  [system:step_start]

  [assistant]
  ## opencode-agent-sdk-python
  ### Purpose
  An open-source Python SDK that serves as a drop-in replacement for Anthropic's
  proprietary `claude_agent_sdk`. It delegates all LLM work to OpenCode — an
  open-source headless server that supports any provider ...
  ...

============================================================
  [result] session  = ses_...
           cost     = $0.024723
           turns    = 1
           is_error = False
============================================================

[*] Message counts: {'system': 2, 'assistant': 1, 'result': 1}
[*] E2E test complete.

What's happening

  1. SDKClient creates an HTTP session against opencode serve
  2. query() sends the user prompt via POST /session/{id}/message
  3. receive_response() yields typed messages: SystemMessage (init, step events), AssistantMessage (LLM text/tool calls), and ResultMessage (cost, session ID, turn count)
  4. disconnect() cleans up the session

Customizing the demo

Set a custom server URL via environment variable:

OPENCODE_SERVER_URL=http://your-host:54321 uv run python scripts/e2e_test.py

Running with Docker

# Start opencode serve
docker compose up -d

# Run the integration test
docker compose run --rm test

The Docker setup uses opencode-ai v1.2.6 and exposes the REST API on port 54321. Pass provider API keys via .env (e.g. ANTHROPIC_API_KEY).

Development

# Install dependencies
uv sync

# Run tests
uv run pytest

# Run demo against a running opencode serve
uv run python scripts/opencode_ai_demo.py

# Interactive multi-turn chat
uv run python scripts/chat.py

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

opencode_agent_sdk-0.4.8.tar.gz (25.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

opencode_agent_sdk-0.4.8-py3-none-any.whl (24.4 kB view details)

Uploaded Python 3

File details

Details for the file opencode_agent_sdk-0.4.8.tar.gz.

File metadata

  • Download URL: opencode_agent_sdk-0.4.8.tar.gz
  • Upload date:
  • Size: 25.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for opencode_agent_sdk-0.4.8.tar.gz
Algorithm Hash digest
SHA256 69a3885e73b780d683f7b4465739c20091f66f4ebd10161b1a97d96a350ae2b3
MD5 9d372fdbf34ac7ad817044789832e6b6
BLAKE2b-256 8ddd9bca500c43eba4e7298768e9baeed8e0c40659474946cd03b8a1d1049c2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for opencode_agent_sdk-0.4.8.tar.gz:

Publisher: publish.yml on dingkwang/opencode-agent-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file opencode_agent_sdk-0.4.8-py3-none-any.whl.

File metadata

File hashes

Hashes for opencode_agent_sdk-0.4.8-py3-none-any.whl
Algorithm Hash digest
SHA256 95ff2c48054af5a0127a088797d6dd3de386226131358a7d5dd3536701064756
MD5 3ec92bd9363083ca79a78e5709dce572
BLAKE2b-256 b686b316efb31d872b0eb921a8c4bd909b35db16db3a00e5eaeab356d6c2721a

See more details on using hashes here.

Provenance

The following attestation bundles were made for opencode_agent_sdk-0.4.8-py3-none-any.whl:

Publisher: publish.yml on dingkwang/opencode-agent-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page