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 running
  • TIMEOUT: Server didn’t respond in time
  • AUTH_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 exist
  • INVALID_MODEL: Model not available
  • SESSION_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 server
  • SESSION_NOT_FOUND: Session ID doesn’t exist
  • SESSION_BUSY: Session already processing a message
  • PERMISSION_DENIED: Auth token invalid or missing
  • TIMEOUT: Operation exceeded timeout
  • INVALID_PARAMETERS: Required parameter missing or invalid
  • SERVER_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: true

Agent 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 wait

Multi-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 user

Testing

Unit Tests

  • Mock ACP server responses
  • Verify correct HTTP/WebSocket calls
  • Test error handling (connection failures, timeouts)

Integration Tests

  • Real opencode acp instance
  • 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 connect action
  • Handle protocol upgrades gracefully

Next Steps

  1. Discover ACP Protocol: Run opencode acp and document actual endpoints
  2. Implement Client Library: TypeScript ACP client matching this spec
  3. Build OpenClaw Tool: Wire client into OpenClaw tool system
  4. Test MVP: Create session + send message via WhatsApp
  5. 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