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.12.tar.gz (26.1 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.12-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: opencode_agent_sdk-0.4.12.tar.gz
  • Upload date:
  • Size: 26.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.16

File hashes

Hashes for opencode_agent_sdk-0.4.12.tar.gz
Algorithm Hash digest
SHA256 6cfde2b8d76648056a734067f43034f75c6bdecb29ce2abdf09f050b255baf9a
MD5 ee63858f737773a04d62d253d52e6a45
BLAKE2b-256 0af271cfe2afa2ce8e90b0a55eeb227ab810395f6e838ded5570c235390ef059

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for opencode_agent_sdk-0.4.12-py3-none-any.whl
Algorithm Hash digest
SHA256 eda5d9da9fed56dad42944b9f9318e2dfa8db26309af57cd45bc56786be78c26
MD5 abb426b9358e480eebd5e2eb50b8fb28
BLAKE2b-256 e3e424d4d3a6d80556a2fa82bdb4fb06b9cdc58a128fbfab9f6a8358184e5b30

See more details on using hashes here.

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