CtrlK
BlogDocsLog inGet started
Tessl Logo

opencode-build-tool

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

Quality

91%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

OpenCode SDK Development

Quick Start: Custom Tool in 3 Steps

  1. Create .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}`
  }
})
  1. Restart OpenCode — tools are auto-discovered.
  2. Filename = tool name: my-tool.tsmy-tool.

Mindset

  • @opencode-ai/pluginTools + Hooks: Add LLM-callable tools, intercept execution, react to events
  • @opencode-ai/sdkClient API: Control OpenCode from external scripts, session management

When 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.

Tool File Locations

.opencode/tool/*.ts          # project-specific
~/.config/opencode/tool/*.ts  # global

Multiple named exports per file → multiple tools: filename_exportname

Anti-Patterns

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()) }

Reference Files

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

Eval Scenarios

Repository
pantheon-org/tekhne
Last updated
First committed

Also appears in

pantheon-ai/opencode-toolkit
In sync

since Mar 14, 2026

Is this your skill?

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.