Skills
Chapter 2 of 4
OpenCode plugins, @opencode-ai/plugin, @opencode-ai/plugin/tui, plugin hooks, custom tools, TUI routes, slots, keymaps, and packaging.
3 minutes · 605 words · 7 sections
Use this skill to implement production-quality OpenCode plugins. Treat the repository’s exported types and runtime as authoritative because plugin APIs are evolving and public docs may lag.
| Need | Plugin target | Import | Configuration |
|---|---|---|---|
| Hooks, tools, auth, providers, model parameters, shell environment | Server | @opencode-ai/plugin | opencode.json or auto-discovered .opencode/plugins/*.{ts,js} |
| Commands, keybindings, routes, dialogs, slots, themes, notifications | TUI | @opencode-ai/plugin/tui | Explicit tui.json plugin entry |
| Both | Two target-only entrypoints | Both imports in separate files | Package exports ./server and ./tui |
Never export server and tui from the same module. Do not use server event hooks as a substitute for interactive TUI APIs.
Read these files before implementing unfamiliar behavior:
packages/plugin/src/index.ts: authoritative server plugin and hook types.packages/plugin/src/tool.ts: custom tool schema, context, permission, metadata, attachments, and result types.packages/plugin/src/tui.ts: authoritative TUI API and module types.packages/opencode/specs/tui-plugins.md: TUI loading, packaging, lifecycle, and API semantics.packages/opencode/src/plugin/shared.ts: target validation, IDs, and entrypoint resolution.packages/opencode/src/plugin/loader.ts: install, compatibility, and import behavior.If these disagree with examples or website docs, follow exported types and runtime behavior, then update stale documentation when appropriate.
Prefer the explicit module object for new server plugins:
import type { Plugin, PluginModule } from '@opencode-ai/plugin';
const server: Plugin = async ({ client, directory }, options) => ({
dispose: async () => {},
});
export default {
id: 'acme.example',
Legacy server-only local plugins may export a plugin function directly. In a legacy module every distinct named export is interpreted as a plugin, so do not export unrelated constants. Prefer a default module object for new code.
TUI plugins always use a default module object:
/** @jsxImportSource @opentui/solid */
import type { TuiPlugin, TuiPluginModule } from '@opencode-ai/plugin/tui';
const tui: TuiPlugin = async (api) => {
api.ui.toast({ message: 'Plugin loaded' });
};
export default {
id: 'acme.example-tui',
File plugins require a stable, non-empty id. npm plugins may derive the ID from the package name, but an explicit namespaced ID makes state, diagnostics, and collision handling clearer.
satisfies against the public plugin type.options; they arrive as unvalidated Record<string, unknown>.process.cwd().AbortSignal for long-running or cancellable work.client.app.log() for structured server logging instead of console.log.Server plugin tests belong under packages/opencode/test/plugin/ or the closest owning subsystem. TUI runtime tests belong under packages/opencode/test/cli/tui/; component-level TUI tests may belong in packages/tui.
Test at least:
Run tests from the package directory, never the repository root. Use bun typecheck from the owning package for type checking.
engines.opencode, and config target are correct.Install this repository
npx skills add sveltejs/ai-tools/plugin marketplace add sveltejs/ai-toolsSkills install per repository, not per chapter — the CLI has no documented per-skill form, so we do not print one.
OpenCode plugins, @opencode-ai/plugin, @opencode-ai/plugin/tui, plugin hooks, custom tools, TUI routes, slots, keymaps, and packaging. Use when creating, editing, reviewing, testing, or publishing server or TUI plugins for OpenCode.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 9 August 2026.SKILL.md, not by matching a directory convention. 2 distinct layouts observed: .agents/skills/*/SKILL.md, tools/skills/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by Svelte, declaring 1 plugin. It is read for editorial metadata only — never as the skill index, which is always the repository tree./sveltejs/ai-tools.md, and each chapter at its own .md URL.3 files · 16 KB
Everything this skill ships beside its prose. All of it is set here, as subchapters of chapter 2.
Documentation the agent loads on demand, rather than up front.