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:

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
npm install @opencode-ai/sdkThree Usage Modes
1. Create Server + Client (Recommended)
Start both server and client, ideal for standalone scripts and automation:
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
| Parameter | Type | Description | Default |
|---|---|---|---|
hostname | string | Server hostname | 127.0.0.1 |
port | number | Server port | 4096 |
signal | AbortSignal | Abort signal for cancellation | undefined |
timeout | number | Server startup timeout (ms) | 2000+ |
config | Config | Config object to override opencode.json | {} |
Source:
packages/sdk/js/src/server.ts:4-10
Configuration Override Example
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:
import { createOpencodeClient } from "@opencode-ai/sdk"
const client = createOpencodeClient({
baseUrl: "http://localhost:4096",
})
// Use client directly
const sessions = await client.session.list()ClientOptions Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
baseUrl | string | Server URL | http://localhost:4096 |
fetch | function | Custom fetch implementation | globalThis.fetch |
parseAs | string | Response parsing: auto, json, text, blob, arrayBuffer, stream, formData | auto |
responseStyle | "data" | "fields" | Return style: data returns only data, fields returns full response | fields |
throwOnError | boolean | Throw on error instead of returning | false |
directory | string | Project 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
// 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:
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
// Node.js doesn't have btoa, use Buffer instead
Authorization: `Basic ${Buffer.from("opencode:password").toString("base64")}`| Scenario | Username | Description |
|---|---|---|
| Default | opencode | Server default username |
| Custom | Value of OPENCODE_SERVER_USERNAME env var | If 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:
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
| Parameter | Type | Description |
|---|---|---|
project | string | Project directory path |
model | string | Model to use (format: provider/model) |
session | string | Session ID to resume |
agent | string | Agent to use (e.g., build, plan) |
signal | AbortSignal | Abort signal for cancellation |
config | Config | Configuration object |
Source:
packages/sdk/js/src/server.ts:12-19
Basic API Usage
Session Management
// 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
// 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)
// 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 listenerFile Operations
// 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
// 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
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 Type | Description |
|---|---|
message.updated | Message content updated |
message.part.updated | Message part updated (includes delta) |
session.status | Session status changed (idle/busy/retry) |
session.idle | Session entered idle state |
permission.updated | Permission request pending |
file.edited | File was edited |
todo.updated | Todo list updated |
For complete event types, see 5.10b API Reference
Type Imports
SDK provides complete TypeScript type definitions:
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
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
// 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
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
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
| Issue | Cause | Solution |
|---|---|---|
| SDK connection failed | Server not running | Run opencode serve first or use createOpencode() |
| Port conflict | Default port 4096 in use | Specify different port port: 4097 |
| Type errors | SDK version mismatch | Update to latest npm update @opencode-ai/sdk |
| Timeout error | Slow server startup or network issues | Increase timeout value |
| Event stream interrupted | Connection dropped | Implement reconnection logic |
| Response format confusion | responseStyle config | Default is fields, returns { data, error, request, response } |
Lesson Summary
You learned:
- Install SDK:
npm install @opencode-ai/sdk - Three usage modes:
createOpencode()- Server + ClientcreateOpencodeClient()- Client onlycreateOpencodeTui()- Launch TUI
- Basic APIs: Session management, message sending, file operations, TUI control
- Event listening: Real-time status change notifications
Related Resources
- 5.10b API Reference - Complete API documentation
- 5.9 Remote Development - HTTP Server details
- Official SDK Docs
Next Lesson Preview
5.10b API Reference will cover all 21 API modules, complete type definitions, and 35+ event types in detail.

