Skip to content

5.10a SDK Basics

TL;DR: Use the JavaScript/TypeScript SDK to control OpenCode programmatically for automated workflows and custom integrations.

Course Notes

Key takeaways from this lesson:

5.10a SDK Basics Notes


What You'll Learn

  • Install and configure the OpenCode SDK
  • Create server and client instances
  • Launch the TUI interface
  • Manage sessions and send messages
  • Listen to real-time events

Your Current Challenges

  • Want to call OpenCode from your own application
  • Want to batch process tasks programmatically
  • Want to build custom integrations (IDE plugins, CI/CD tools, etc.)
  • Want to automate OpenCode operations in scripts

SDK Architecture Overview

┌─────────────────────────────────────────────────────────┐
│                    Your Application                       │
├─────────────────────────────────────────────────────────┤
│                   @opencode-ai/sdk                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │
│  │createOpencode│  │createOpencode│  │createOpencode│    │
│  │             │  │   Client    │  │    Tui      │      │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘      │
│         │                │                │              │
│  Server+Client     Client Only      Launch TUI          │
└─────────┼────────────────┼────────────────┼─────────────┘
          │                │                │
          ▼                ▼                ▼
┌─────────────────────────────────────────────────────────┐
│                  OpenCode Server                         │
│            HTTP API (default port 4096)                  │
└─────────────────────────────────────────────────────────┘

Install SDK

bash
npm install @opencode-ai/sdk

Three Usage Modes

Start both server and client, ideal for standalone scripts and automation:

typescript
import { createOpencode } from "@opencode-ai/sdk"

const { client, server } = await createOpencode()

// Use client to call APIs
const sessions = await client.session.list()
console.log(`Currently ${sessions.data?.length} sessions`)

// Close server when done
server.close()

ServerOptions Parameters

ParameterTypeDescriptionDefault
hostnamestringServer hostname127.0.0.1
portnumberServer port4096
signalAbortSignalAbort signal for cancellationundefined
timeoutnumberServer startup timeout (ms)2000+
configConfigConfig object to override opencode.json{}

Source: packages/sdk/js/src/server.ts:4-10

Configuration Override Example

typescript
import { createOpencode } from "@opencode-ai/sdk"

const opencode = await createOpencode({
  hostname: "127.0.0.1",
  port: 4097,  // Use different port to avoid conflicts
  timeout: 10000,
  config: {
    model: "anthropic/claude-opus-4-5-thinking",
    logLevel: "DEBUG",
  },
})

console.log(`Server running at ${opencode.server.url}`)

// Close when done
opencode.server.close()

2. Client-Only Mode

Connect to a running OpenCode instance, ideal for plugin development:

typescript
import { createOpencodeClient } from "@opencode-ai/sdk"

const client = createOpencodeClient({
  baseUrl: "http://localhost:4096",
})

// Use client directly
const sessions = await client.session.list()

ClientOptions Parameters

ParameterTypeDescriptionDefault
baseUrlstringServer URLhttp://localhost:4096
fetchfunctionCustom fetch implementationglobalThis.fetch
parseAsstringResponse parsing: auto, json, text, blob, arrayBuffer, stream, formDataauto
responseStyle"data" | "fields"Return style: data returns only data, fields returns full responsefields
throwOnErrorbooleanThrow on error instead of returningfalse
directorystringProject directory (passed via X-Opencode-Directory header)undefined

Source: packages/sdk/js/src/gen/client/types.gen.ts:10-52, packages/sdk/js/src/client.ts:8

Switching Project Directories

typescript
// Connect to different projects
const client = createOpencodeClient({
  baseUrl: "http://localhost:4096",
  directory: "/path/to/my-project",
})

Remote Connection (with Authentication)

When connecting to a remote OpenCode server with OPENCODE_SERVER_PASSWORD set, pass Basic Auth via headers:

typescript
import { createOpencodeClient } from "@opencode-ai/sdk"

// Remote connection (with auth)
const client = createOpencodeClient({
  baseUrl: "http://192.168.1.100:4096",
  headers: {
    // Basic Auth format: Base64(username:password)
    // Use btoa() in browser/Edge Runtime
    Authorization: `Basic ${btoa("opencode:your-password")}`
  },
  directory: "/projects/my-app"  // Specify remote project directory
})
Use Buffer in Node.js
typescript
// Node.js doesn't have btoa, use Buffer instead
Authorization: `Basic ${Buffer.from("opencode:password").toString("base64")}`
ScenarioUsernameDescription
DefaultopencodeServer default username
CustomValue of OPENCODE_SERVER_USERNAME env varIf server has custom username

Source: packages/opencode/src/server/server.ts:84-87 (Basic Auth middleware)


3. Launch TUI Interface

Programmatically start OpenCode's terminal interface:

typescript
import { createOpencodeTui } from "@opencode-ai/sdk"

const tui = createOpencodeTui({
  project: "/path/to/my-project",
  model: "anthropic/claude-opus-4-5-thinking",
  session: "abc123",  // Resume specific session
  agent: "build",
})

// User can interact in TUI
// ...

// Close TUI
tui.close()

TuiOptions Parameters

ParameterTypeDescription
projectstringProject directory path
modelstringModel to use (format: provider/model)
sessionstringSession ID to resume
agentstringAgent to use (e.g., build, plan)
signalAbortSignalAbort signal for cancellation
configConfigConfiguration object

Source: packages/sdk/js/src/server.ts:12-19


Basic API Usage

Session Management

typescript
// Create new session
const session = await client.session.create({
  body: { title: "My Task" },
})
console.log(`Created session: ${session.data?.id}`)

// List all sessions
const sessions = await client.session.list()

// Get single session
const detail = await client.session.get({
  path: { id: session.data!.id },
})

// Delete session
await client.session.delete({
  path: { id: session.data!.id },
})

Send Messages

typescript
// Send prompt and wait for AI response
const result = await client.session.prompt({
  path: { id: sessionId },
  body: {
    model: { providerID: "anthropic", modelID: "claude-opus-4-5-thinking" },
    parts: [{ type: "text", text: "Please analyze the performance issues in this code" }],
  },
})

// Inject context (without triggering AI response)
await client.session.prompt({
  path: { id: sessionId },
  body: {
    noReply: true,
    parts: [{ type: "text", text: "You are a professional code review assistant." }],
  },
})

Async Send (Don't Wait for Response)

typescript
// Returns immediately, ideal for long tasks
await client.session.promptAsync({
  path: { id: sessionId },
  body: {
    parts: [{ type: "text", text: "Please refactor the entire module" }],
  },
})

// Get response via event listener

File Operations

typescript
// Search text content
const textResults = await client.find.text({
  query: { pattern: "function.*opencode" },
})

// Find files (supports glob patterns)
const files = await client.find.files({
  query: { 
    query: "*.ts", 
    type: "file",
    limit: 100,  // Max 100 results
  },
})

// Find directories
const dirs = await client.find.files({
  query: { query: "src", type: "directory" },
})

// Read file content
const content = await client.file.read({
  query: { path: "src/index.ts" },
})

// Get file status (git changes)
const status = await client.file.status()

TUI Control

typescript
// Append text to input box
await client.tui.appendPrompt({
  body: { text: "Please check this file" },
})

// Submit current input
await client.tui.submitPrompt()

// Clear input
await client.tui.clearPrompt()

// Show notification
await client.tui.showToast({
  body: { 
    message: "Task completed!", 
    variant: "success",
    duration: 3000,  // Show for 3 seconds
  },
})

// Open dialogs
await client.tui.openHelp()
await client.tui.openSessions()
await client.tui.openThemes()
await client.tui.openModels()

// Execute TUI commands
await client.tui.executeCommand({
  body: { command: "agent_cycle" },
})

Real-time Event Listening

Subscribe to Event Stream

typescript
const events = await client.event.subscribe()

for await (const event of events.stream) {
  console.log(`Event type: ${event.type}`)
  console.log(`Event data:`, event.properties)
  
  // Handle by event type
  switch (event.type) {
    case "message.updated":
      console.log("Message updated:", event.properties.info)
      break
    case "session.idle":
      console.log("Session idle:", event.properties.sessionID)
      break
    case "permission.updated":
      console.log("Permission request:", event.properties)
      break
  }
}

Common Event Types

Event TypeDescription
message.updatedMessage content updated
message.part.updatedMessage part updated (includes delta)
session.statusSession status changed (idle/busy/retry)
session.idleSession entered idle state
permission.updatedPermission request pending
file.editedFile was edited
todo.updatedTodo list updated

For complete event types, see 5.10b API Reference


Type Imports

SDK provides complete TypeScript type definitions:

typescript
import type { 
  // Core types
  Session,
  Message,
  Part,
  
  // Event types
  Event,
  EventMessageUpdated,
  EventSessionIdle,
  
  // Config types
  Config,
  AgentConfig,
  ProviderConfig,
  
  // Others
  Todo,
  Permission,
  Agent,
  Provider,
  Model,
} from "@opencode-ai/sdk"

Error Handling

Standard Error Handling

typescript
try {
  const session = await client.session.get({ 
    path: { id: "invalid-id" } 
  })
} catch (error) {
  console.error("Failed to get session:", (error as Error).message)
}

Using throwOnError Option

typescript
// Global configuration
const client = createOpencodeClient({
  baseUrl: "http://localhost:4096",
  throwOnError: true,  // Throw on all request errors
})

// Or use in single request
const result = await client.session.get({
  path: { id: sessionId },
  throwOnError: true,
})

Check Return Value

typescript
const result = await client.session.get({
  path: { id: sessionId },
})

if (result.error) {
  console.error("Error:", result.error)
} else {
  console.log("Session:", result.data)
}

Practical Example: Batch Code Review

typescript
import { createOpencode } from "@opencode-ai/sdk"
import { readdir } from "fs/promises"

async function batchCodeReview(directory: string) {
  const { client, server } = await createOpencode({
    config: {
      model: "anthropic/claude-opus-4-5-thinking",
    },
  })

  try {
    // Create session
    const session = await client.session.create({
      body: { title: `Batch Code Review - ${directory}` },
    })
    const sessionId = session.data!.id

    // Find all TypeScript files
    const files = await client.find.files({
      query: { query: "*.ts", type: "file", directory },
    })

    console.log(`Found ${files.data?.length} files`)

    // Review each file
    for (const file of files.data ?? []) {
      console.log(`Reviewing: ${file}`)
      
      await client.session.prompt({
        path: { id: sessionId },
        body: {
          parts: [{ 
            type: "text", 
            text: `Please review file ${file} for potential issues and improvement suggestions.` 
          }],
        },
      })
    }

    console.log("Review complete!")
  } finally {
    server.close()
  }
}

batchCodeReview("./src")

Common Pitfalls

IssueCauseSolution
SDK connection failedServer not runningRun opencode serve first or use createOpencode()
Port conflictDefault port 4096 in useSpecify different port port: 4097
Type errorsSDK version mismatchUpdate to latest npm update @opencode-ai/sdk
Timeout errorSlow server startup or network issuesIncrease timeout value
Event stream interruptedConnection droppedImplement reconnection logic
Response format confusionresponseStyle configDefault is fields, returns { data, error, request, response }

Lesson Summary

You learned:

  1. Install SDK: npm install @opencode-ai/sdk
  2. Three usage modes:
    • createOpencode() - Server + Client
    • createOpencodeClient() - Client only
    • createOpencodeTui() - Launch TUI
  3. Basic APIs: Session management, message sending, file operations, TUI control
  4. Event listening: Real-time status change notifications


Next Lesson Preview

5.10b API Reference will cover all 21 API modules, complete type definitions, and 35+ event types in detail.