API Contract: OpenClaw opencode Tool
Version: 1.0.0-draft
Date: 2026-02-12
Overview
This document defines the interface between OpenClaw agents and the ACP client tool. It specifies the exact function signatures, parameters, return types, and behaviors that OpenClaw agents will use to control OpenCode sessions.
Tool Registration
Tool Name: opencode
Description: Manage OpenCode AI coding agent sessions via Agent Client Protocol (ACP).
Capabilities:
- Create and manage coding agent sessions
- Send instructions/prompts to agents
- Monitor progress and status
- Stream real-time updates
- Handle permission requests
- Export session data
Actions
1. connect
Description: Establish connection to an OpenCode ACP server.
Parameters:
{
action: 'connect',
url: string, // e.g., 'http://localhost:3333'
name?: string, // Instance name (default: derived from URL)
auth_token?: string, // Optional auth token
timeout_ms?: number // Connection timeout (default: 5000)
}Returns:
{
success: boolean,
instance: string, // Instance name
url: string,
connected: boolean,
server_version?: string,
message?: string // Success/error message
}Example:
{
"action": "connect",
"url": "http://localhost:3333",
"name": "local"
}
// Response:
{
"success": true,
"instance": "local",
"url": "http://localhost:3333",
"connected": true,
"server_version": "1.2.3",
"message": "Connected to OpenCode ACP server"
}Errors:
ECONNREFUSED: Server not runningTIMEOUT: Server didn’t respond in timeAUTH_FAILED: Invalid auth token
2. disconnect
Description: Close connection to an ACP server.
Parameters:
{
action: 'disconnect',
instance?: string // Instance name (default: all)
}Returns:
{
success: boolean,
disconnected: string[], // List of instance names
message?: string
}3. create_session
Description: Create a new OpenCode coding agent session.
Parameters:
{
action: 'create_session',
instance?: string, // Which ACP server (default: first/default)
project: string, // Project directory path
message?: string, // Initial prompt/instruction
model?: string, // LLM model (e.g., 'anthropic/claude-sonnet-4')
agent?: string, // Agent type (default: 'default')
session_name?: string, // Human-readable name
resume?: boolean, // Resume last session in project (default: false)
timeout_ms?: number // Session creation timeout (default: 10000)
}Returns:
{
success: boolean,
session_id: string, // UUID or human-readable ID
instance: string,
project: string,
model: string,
status: 'created' | 'resumed',
message?: string
}Example:
{
"action": "create_session",
<<<<<<< HEAD
"project": "/workspace/projects/api-server",
=======
"project": "repos/api-server",
>>>>>>> f146a548fbab991798ce91719b88cbf1f064588a
"message": "Add rate limiting to /login endpoint",
"model": "anthropic/claude-sonnet-4",
"session_name": "api-ratelimit"
}
// Response:
{
"success": true,
"session_id": "abc123",
"instance": "local",
<<<<<<< HEAD
"project": "/workspace/projects/api-server",
=======
"project": "repos/api-server",
>>>>>>> f146a548fbab991798ce91719b88cbf1f064588a
"model": "anthropic/claude-sonnet-4",
"status": "created",
"message": "Session abc123 created"
}Errors:
PROJECT_NOT_FOUND: Project directory doesn’t existINVALID_MODEL: Model not availableSESSION_LIMIT: Too many active sessions
4. list_sessions
Description: List active OpenCode sessions.
Parameters:
{
action: 'list_sessions',
instance?: string, // Filter by instance (default: all)
project?: string, // Filter by project path
status?: 'active' | 'paused' | 'completed' | 'failed',
limit?: number // Max results (default: 50)
}Returns:
{
success: boolean,
sessions: Array<{
session_id: string,
instance: string,
project: string,
name?: string,
status: 'active' | 'paused' | 'completed' | 'failed',
model: string,
created: string, // ISO 8601 timestamp
last_active: string, // ISO 8601 timestamp
message_count: number,
files_changed: number,
tokens_used: number
}>,
total: number,
message?: string
}Example:
{
"action": "list_sessions",
"status": "active"
}
// Response:
{
"success": true,
"sessions": [
{
"session_id": "abc123",
"instance": "local",
<<<<<<< HEAD
"project": "/workspace/projects/api-server",
=======
"project": "repos/api-server",
>>>>>>> f146a548fbab991798ce91719b88cbf1f064588a
"name": "api-ratelimit",
"status": "active",
"model": "anthropic/claude-sonnet-4",
"created": "2026-02-12T07:45:00Z",
"last_active": "2026-02-12T08:00:00Z",
"message_count": 3,
"files_changed": 4,
"tokens_used": 12500
}
],
"total": 1
}5. attach_session
Description: Attach to an existing session (resume or observe).
Parameters:
{
action: 'attach_session',
session_id: string,
subscribe?: boolean, // Subscribe to real-time updates (default: true)
timeout_ms?: number
}Returns:
{
success: boolean,
session_id: string,
instance: string,
project: string,
status: 'active' | 'paused' | 'completed' | 'failed',
last_message?: string, // Last user or agent message
subscribed: boolean, // WebSocket subscription active
message?: string
}Example:
{
"action": "attach_session",
"session_id": "abc123"
}
// Response:
{
"success": true,
"session_id": "abc123",
"instance": "local",
<<<<<<< HEAD
"project": "/workspace/projects/api-server",
=======
"project": "repos/api-server",
>>>>>>> f146a548fbab991798ce91719b88cbf1f064588a
"status": "active",
"last_message": "Rate limiter added to /login. Should I write tests?",
"subscribed": true,
"message": "Attached to session abc123"
}6. send_message
Description: Send a message/instruction to an OpenCode session.
Parameters:
{
action: 'send_message',
session_id: string,
message: string, // User prompt/instruction
wait_for_completion?: boolean, // Block until agent responds (default: false)
timeout_ms?: number // Only if wait_for_completion=true
}Returns:
{
success: boolean,
session_id: string,
message_id: string, // ID of sent message
status: 'sent' | 'delivered' | 'completed',
response?: string, // Only if wait_for_completion=true
message?: string
}Example:
{
"action": "send_message",
"session_id": "abc123",
"message": "Yes, write integration tests for the rate limiter"
}
// Response:
{
"success": true,
"session_id": "abc123",
"message_id": "msg456",
"status": "sent",
"message": "Message sent to session abc123"
}7. get_status
Description: Get detailed status of a session.
Parameters:
{
action: 'get_status',
session_id: string
}Returns:
{
success: boolean,
session_id: string,
instance: string,
project: string,
status: 'active' | 'paused' | 'completed' | 'failed',
progress?: {
current_task?: string, // e.g., "Writing tests"
files_open: number,
files_changed: number,
files_created: number,
commands_run: number,
last_command?: string,
tests_passed?: number,
tests_failed?: number
},
model: string,
tokens: {
input: number,
output: number,
total: number,
cost_usd?: number
},
timing: {
created: string, // ISO 8601
last_active: string,
duration_seconds: number
},
message?: string
}Example:
{
"action": "get_status",
"session_id": "abc123"
}
// Response:
{
"success": true,
"session_id": "abc123",
"instance": "local",
<<<<<<< HEAD
"project": "/workspace/projects/api-server",
=======
"project": "repos/api-server",
>>>>>>> f146a548fbab991798ce91719b88cbf1f064588a
"status": "active",
"progress": {
"current_task": "Writing integration tests",
"files_open": 3,
"files_changed": 5,
"files_created": 2,
"commands_run": 8,
"last_command": "npm test",
"tests_passed": 12,
"tests_failed": 0
},
"model": "anthropic/claude-sonnet-4",
"tokens": {
"input": 8500,
"output": 4200,
"total": 12700,
"cost_usd": 0.084
},
"timing": {
"created": "2026-02-12T07:45:00Z",
"last_active": "2026-02-12T08:15:00Z",
"duration_seconds": 1800
}
}8. get_messages
Description: Retrieve message history from a session.
Parameters:
{
action: 'get_messages',
session_id: string,
limit?: number, // Max messages (default: 50)
since?: string, // ISO 8601 timestamp
role?: 'user' | 'agent' | 'system'
}Returns:
{
success: boolean,
session_id: string,
messages: Array<{
message_id: string,
role: 'user' | 'agent' | 'system',
content: string,
timestamp: string, // ISO 8601
metadata?: {
files_changed?: string[],
command_run?: string,
tokens_used?: number
}
}>,
total: number,
message?: string
}9. terminate_session
Description: Stop and clean up an OpenCode session.
Parameters:
{
action: 'terminate_session',
session_id: string,
reason?: string, // Optional reason for logs
save_state?: boolean // Save session state before terminating (default: true)
}Returns:
{
success: boolean,
session_id: string,
status: 'terminated',
saved_state: boolean,
message?: string
}10. export_session
Description: Export session data for logging/analysis.
Parameters:
{
action: 'export_session',
session_id: string,
format?: 'json' | 'markdown', // Default: 'json'
include_messages?: boolean, // Default: true
include_files?: boolean, // Default: false (file contents)
include_stats?: boolean // Default: true
}Returns:
{
success: boolean,
session_id: string,
format: 'json' | 'markdown',
data: string | object, // JSON object or markdown string
message?: string
}Example (JSON format):
{
"action": "export_session",
"session_id": "abc123",
"format": "json"
}
// Response:
{
"success": true,
"session_id": "abc123",
"format": "json",
"data": {
"session_id": "abc123",
<<<<<<< HEAD
"project": "/workspace/projects/api-server",
=======
"project": "repos/api-server",
>>>>>>> f146a548fbab991798ce91719b88cbf1f064588a
"created": "2026-02-12T07:45:00Z",
"completed": "2026-02-12T08:30:00Z",
"duration_seconds": 2700,
"messages": [...],
"files_changed": [...],
"tokens": {...},
"outcome": "success"
}
}11. get_stats
Description: Get token usage and cost statistics.
Parameters:
{
action: 'get_stats',
session_id?: string, // Specific session, or omit for instance totals
instance?: string // Which instance (default: all)
}Returns:
{
success: boolean,
scope: 'session' | 'instance' | 'all',
stats: {
sessions_total: number,
sessions_active: number,
tokens: {
input_total: number,
output_total: number,
total: number,
cost_usd: number
},
by_model?: {
[model: string]: {
tokens: number,
cost_usd: number
}
}
},
message?: string
}Real-Time Events (WebSocket)
When attach_session or send_message with streaming enabled, the tool receives real-time events via WebSocket.
Event Types:
agent.message
{
type: 'agent.message',
session_id: string,
content: string,
timestamp: string
}agent.file_opened
{
type: 'agent.file_opened',
session_id: string,
path: string,
timestamp: string
}agent.file_changed
{
type: 'agent.file_changed',
session_id: string,
path: string,
additions: number,
deletions: number,
timestamp: string
}agent.command_run
{
type: 'agent.command_run',
session_id: string,
command: string,
exit_code?: number,
timestamp: string
}agent.permission_request
{
type: 'agent.permission_request',
session_id: string,
request_id: string,
action: string, // e.g., 'execute_command', 'modify_file'
details: {
command?: string,
file?: string,
reason?: string
},
timestamp: string
}agent.progress
{
type: 'agent.progress',
session_id: string,
task: string, // e.g., "Writing tests"
percent?: number, // 0-100 if estimable
timestamp: string
}agent.complete
{
type: 'agent.complete',
session_id: string,
summary: string,
outcome: 'success' | 'failed' | 'cancelled',
timestamp: string
}agent.error
{
type: 'agent.error',
session_id: string,
error: string,
recoverable: boolean,
timestamp: string
}Permission Approval Flow
Request (OpenCode → OpenClaw)
Agent needs permission, sends agent.permission_request event.
Approval (OpenClaw → OpenCode)
{
action: 'approve_permission',
session_id: string,
request_id: string,
approved: boolean,
reason?: string // Optional user reason
}Returns:
{
success: boolean,
request_id: string,
status: 'approved' | 'denied',
message?: string
}Error Handling
Standard Error Response
{
success: false,
error: {
code: string, // e.g., 'SESSION_NOT_FOUND'
message: string, // Human-readable
details?: object // Additional context
}
}Common Error Codes
INSTANCE_NOT_CONNECTED: No connection to ACP serverSESSION_NOT_FOUND: Session ID doesn’t existSESSION_BUSY: Session already processing a messagePERMISSION_DENIED: Auth token invalid or missingTIMEOUT: Operation exceeded timeoutINVALID_PARAMETERS: Required parameter missing or invalidSERVER_ERROR: ACP server returned 5xx
Tool Configuration (Gateway Config)
Location: ~/.openclaw/config/gateway.yaml
tools:
opencode:
enabled: true
instances:
- name: local
url: http://localhost:3333
default: true
auto_connect: true
- name: vps-heavy
url: http://build-server.example.com:3333
auth_token_env: OPENCODE_VPS_TOKEN
auto_connect: false
defaults:
model: anthropic/claude-sonnet-4
agent: default
timeout_ms: 30000
features:
streaming: true
permission_approval: true
auto_reconnect: true
state_persistence: trueAgent Usage Examples
Simple Task
# Agent receives: "Add rate limiting to the login endpoint in api-server"
opencode(
action='create_session',
<<<<<<< HEAD
project='/workspace/projects/api-server',
=======
project='repos/api-server',
>>>>>>> f146a548fbab991798ce91719b88cbf1f064588a
message='Add rate limiting to /login endpoint. Use express-rate-limit package.'
)
# Tool returns session_id, agent can monitor or waitMulti-Step Interaction
# Create session
session = opencode(action='create_session', project='...', message='...')
session_id = session['session_id']
# Check status periodically
status = opencode(action='get_status', session_id=session_id)
# If agent asks a question via WebSocket event:
# (OpenClaw receives agent.message event)
# Agent formulates response, sends:
opencode(
action='send_message',
session_id=session_id,
message='Yes, write integration tests'
)Parallel Review
# User: "Review PRs 86, 87, 88 in parallel"
sessions = []
for pr_num in [86, 87, 88]:
session = opencode(
action='create_session',
project=f'/tmp/pr-{pr_num}-review',
message=f'Review PR #{pr_num}. Check code quality, security, test coverage.'
)
sessions.append(session['session_id'])
# Monitor all sessions
for sid in sessions:
status = opencode(action='get_status', session_id=sid)
# Format and report to userTesting
Unit Tests
- Mock ACP server responses
- Verify correct HTTP/WebSocket calls
- Test error handling (connection failures, timeouts)
Integration Tests
- Real
opencode acpinstance - Create session, send message, verify response
- Test reconnection after disconnect
End-to-End
- Full flow: WhatsApp message → OpenClaw agent → ACP → agent response → WhatsApp
- Permission approval flow
- Multi-session management
Versioning
Current: 1.0.0-draft
Stability: Draft — subject to change based on ACP protocol discovery
When ACP is documented:
- Lock to specific ACP version
- Add version negotiation in
connectaction - Handle protocol upgrades gracefully
Next Steps
- Discover ACP Protocol: Run
opencode acpand document actual endpoints - Implement Client Library: TypeScript ACP client matching this spec
- Build OpenClaw Tool: Wire client into OpenClaw tool system
- Test MVP: Create session + send message via WhatsApp
- Iterate: Refine based on real-world usage
References
- OpenCode: https://github.com/sweetpad-dev/opencode <<<<<<< HEAD
- OpenClaw Tools:
/app/gateway/src/tools/ - Existing Bridge Plugin:
/workspace/projects/ai-dev/plugins/opencode-bridge/======= - OpenClaw Tools:
app/gateway/src/tools/(relative to OpenClaw root) - Existing Bridge Plugin:
projects/ai-dev/plugins/opencode-bridge/(if it exists)
f146a548fbab991798ce91719b88cbf1f064588a