OpenCode SDK Development
Guide for creating custom tools and plugins using the OpenCode SDK.
Overview
OpenCode provides two main packages for SDK development:
Package Purpose
@opencode-ai/sdk
Client SDK for interacting with OpenCode server (sessions, messages, files)
@opencode-ai/plugin
Plugin system for creating custom tools with schema validation
Quick Start: Custom Tools
Custom tools extend OpenCode's capabilities. Tools are TypeScript/JavaScript files auto-discovered from:
-
Local: .opencode/tool/ in project directory
-
Global: ~/.config/opencode/tool/
The filename becomes the tool name.
Basic Tool Structure
import { tool } from "@opencode-ai/plugin"
export default tool({ description: "Brief description of what the tool does", args: { paramName: tool.schema.string().describe("Parameter description") }, async execute(args, context) { // context provides: sessionID, messageID, agent, abort return "Result string returned to the AI" } })
Schema Definition
Use tool.schema (which is Zod) for argument validation:
args: { // String with description query: tool.schema.string().describe("Search query"),
// Optional string path: tool.schema.string().optional().describe("File path"),
// Number with constraints limit: tool.schema.number().min(1).max(100).default(10).describe("Max results"),
// Enum/literal union format: tool.schema.enum(["json", "text"]).describe("Output format"),
// Boolean recursive: tool.schema.boolean().default(false).describe("Search recursively") }
Tool Context
The execute function receives a context object:
type ToolContext = { sessionID: string // Current session ID messageID: string // Current message ID agent: string // Current agent identifier abort: AbortSignal // Signal for cancellation }
Example: File Search Tool
import { tool } from "@opencode-ai/plugin" import { $ } from "bun"
export default tool({
description: "Search for files matching a pattern",
args: {
pattern: tool.schema.string().describe("Glob pattern to match"),
directory: tool.schema.string().default(".").describe("Directory to search")
},
async execute({ pattern, directory }) {
const result = await $find ${directory} -name "${pattern}".text()
return result || "No files found"
}
})
Plugin Development
Plugins provide more comprehensive integrations with hooks for events, authentication, and tool modification.
Plugin Structure
import type { Plugin } from "@opencode-ai/plugin"
const plugin: Plugin = async (input) => { const { client, project, directory, worktree, $ } = input
return { // Custom tools tool: { myTool: tool({ /* definition */ }) },
// Event hooks
event: async ({ event }) => { /* handle events */ },
// Configuration hooks
config: async (config) => { /* modify config */ },
// Message hooks
"chat.message": async (input, output) => { /* modify messages */ },
// Tool execution hooks
"tool.execute.before": async (input, output) => { /* pre-processing */ },
"tool.execute.after": async (input, output) => { /* post-processing */ }
} }
export default plugin
Available Hooks
Hook Purpose
event
Handle real-time events from server
config
Modify configuration on load
tool
Register custom tools
auth
Custom authentication providers
chat.message
Modify messages before sending
chat.params
Modify LLM parameters (temperature, topP)
permission.ask
Handle permission requests
tool.execute.before
Pre-process tool arguments
tool.execute.after
Post-process tool output
SDK Client Usage
The SDK client provides programmatic access to OpenCode functionality.
Initialization
import { createOpencode, createOpencodeClient } from "@opencode-ai/sdk"
// Create both client and server const { client, server } = await createOpencode({ hostname: "127.0.0.1", port: 4096, timeout: 5000 })
// Or just the client const client = createOpencodeClient({ baseUrl: "http://127.0.0.1:4096" })
Client API Categories
Category Methods
client.session
list, create, get, delete, prompt, messages, fork, share
client.project
list, current
client.file
list, read, status
client.find
text, files, symbols
client.tool
ids, list
client.event
subscribe (SSE streaming)
client.mcp
status, add
client.tui
appendPrompt, submitPrompt, showToast
Session Management
// List sessions const { data: sessions } = await client.session.list()
// Create session const { data: session } = await client.session.create()
// Send prompt const { data: response } = await client.session.prompt({ path: { id: sessionId }, body: { parts: [{ type: "text", text: "Your message here" }] } })
// Get messages const { data: messages } = await client.session.messages({ path: { id: sessionId } })
Event Streaming
const result = await client.event.subscribe()
for await (const event of result.events) { console.log("Event:", event.type, event.data) }
Installation
Install SDK
npm install @opencode-ai/sdk
Install plugin package (for tools)
npm install @opencode-ai/plugin
Requires TypeScript >= 4.9.
Tool File Location
Location Scope
.opencode/tool/*.ts
Project-specific tools
~/.config/opencode/tool/*.ts
Global tools for all projects
Multiple exports create multiple tools: filename_exportname .
Best Practices
-
Clear Descriptions: Write concise, action-oriented descriptions for tools and parameters
-
Schema Validation: Use Zod schemas to validate all inputs before processing
-
Error Handling: Return meaningful error messages as strings
-
Abort Signal: Check context.abort for long-running operations
-
Type Safety: Use TypeScript for full type inference from schemas
-
Minimal Dependencies: Keep tools lightweight and focused
Common Patterns
Cross-Language Tool
import { tool } from "@opencode-ai/plugin" import { $ } from "bun"
export default tool({
description: "Run Python analysis script",
args: {
file: tool.schema.string().describe("File to analyze")
},
async execute({ file }) {
return await $python3 analyze.py ${file}.text()
}
})
Tool with Context
import { tool } from "@opencode-ai/plugin"
export default tool({ description: "Get current session info", args: {}, async execute(args, context) { return JSON.stringify({ session: context.sessionID, message: context.messageID, agent: context.agent }, null, 2) } })
Troubleshooting
Tool not appearing:
-
Verify file is in .opencode/tool/ or ~/.config/opencode/tool/
-
Check file exports a valid tool definition
-
Restart OpenCode to reload tools
Schema errors:
-
Ensure all required args are provided
-
Check type constraints (string vs number)
-
Verify optional fields use .optional()
Execution errors:
-
Check execute returns a string
-
Verify async operations complete
-
Handle errors and return error messages as strings
Additional Resources
Reference Files
For detailed API documentation:
-
references/sdk-api.md
-
Complete SDK client API reference
-
references/plugin-api.md
-
Full plugin hooks and types
Example Files
Working examples in examples/ :
-
examples/basic-tool.ts
-
Simple tool implementation
-
examples/full-plugin.ts
-
Complete plugin with hooks
External Documentation
-
OpenCode SDK Docs
-
Custom Tools Guide
-
OpenCode GitHub