Build custom tools and plugins using the OpenCode SDK packages. Use when creating custom tools, implementing tool schemas, building plugins, managing OpenCode sessions, using opencode-ai/sdk or opencode-ai/plugin, creating a tool.ts file, writing an execute handler, using tool.schema, ToolContext, createOpencode, plugin hooks, custom auth, automating OpenCode from a script, building a CI tool, or integrating external APIs. Keywords: Zod schema, execute handler, event streaming, session management, abort signal, tool discovery, multiple tools per file, tool factory.
73
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
.opencode/tool/my-tool.ts:import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Brief description of what the tool does",
args: {
query: tool.schema.string().describe("Search query")
},
async execute({ query }, { abort }) {
return `Result for: ${query}`
}
})my-tool.ts → my-tool.@opencode-ai/plugin — Tools + Hooks: Add LLM-callable tools, intercept execution, react to events@opencode-ai/sdk — Client API: Control OpenCode from external scripts, session managementWhen to use: Adding new capabilities the agent doesn't have, automating OpenCode from CI/scripts, or integrating external APIs as first-class tools.
When NOT to use: Built-in tool exists (client.tool.list()). Need shell (use $ from Bun). Logic belongs in system prompt (AGENTS.md). Need MCP.
Full decision guide in advanced-patterns.md.
.opencode/tool/*.ts # project-specific
~/.config/opencode/tool/*.ts # globalMultiple named exports per file → multiple tools: filename_exportname
NEVER return non-string from execute. WHY: The tool runtime expects a string response; returning an object throws at runtime.
// BAD - throws at runtime
async execute({ query }) { return { results: [] } }
// GOOD - serialize first
async execute({ query }) { return JSON.stringify({ results: [] }) }NEVER import { tool } from "@opencode-ai/sdk". WHY: The SDK package has no tool() export. The tool factory is only in @opencode-ai/plugin.
// BAD - import error at runtime
import { tool } from "@opencode-ai/sdk"
// GOOD
import { tool } from "@opencode-ai/plugin"NEVER ignore the abort signal in long-running operations. WHY: Ignoring abort leaves processes dangling after the user cancels, consuming resources.
// BAD - dangling fetch after cancel
async execute({ url }) { return await fetch(url).then(r => r.text()) }
// GOOD - propagate abort
async execute({ url }, { abort }) { return await fetch(url, { signal: abort }).then(r => r.text()) }Run bun run opencode run "list tools" to verify your tool is discovered and named correctly.
---
description: custom tools opencode SDK plugin execute handler abort signal Zod schema session management event streaming
---a1083f4
Also appears in
since Mar 14, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.