Skip to main content

Plugins

Plugins extend OpenCode with custom tools, lifecycle hooks, middleware, and third-party integrations. They can be loaded from npm packages, local file paths, or installed interactively using the plugin CLI commands.

Overview

A plugin can:

  • Register custom tools for the AI agent to use
  • Hook into tool execution lifecycle (before/after)
  • Add middleware for message processing
  • Provide configuration schemas and defaults
  • Integrate with external APIs and services

Configuration

Plugins are declared in opencode.json under the plugin key:

{
"plugin": [
"opencode-helicone-session",
"@my-org/custom-plugin",
"./.opencode/plugins/internal-tools.mjs"
]
}

Each entry is a module specifier: an npm package name, a scoped npm package, or a relative file path.

Plugin Locations

Plugins can reside in several places:

LocationScopeDescription
.opencode/plugins/ProjectPer-project plugins, version-controlled
~/.config/opencode/plugins/UserGlobal plugins available to all projects
npm packagesSystemInstalled via package manager

Local Plugin Example

Create a plugin file at .opencode/plugins/custom-tools.mjs:

import { tool } from 'opencode-ai/sdk';

export default {
name: 'project-tools',
version: '0.1.0',
tools: [
tool({
name: 'query_internal_api',
description: 'Query the internal company API',
parameters: {
type: 'object',
properties: {
endpoint: { type: 'string' },
params: { type: 'object' }
}
},
execute: async ({ endpoint, params }) => {
const res = await fetch(`https://api.internal/${endpoint}`, {
headers: { Authorization: `Bearer ${process.env.INTERNAL_TOKEN}` }
});
return res.json();
}
})
]
};

Installing Plugins

Use the opencode plugin command to install plugins from npm:

# Install a plugin
opencode plugin opencode-helicone-session

# Install with a specific version
opencode plugin opencode-helicone-session@1.2.0

# Install globally (available across all projects)
opencode plugin opencode-helicone-session --global

# Force reinstall, replacing existing version
opencode plugin opencode-helicone-session --force

The plugin command can also be invoked with the shorthand plug:

opencode plug @my-org/custom-plugin
opencode plug @my-org/custom-plugin -g # global
opencode plug @my-org/custom-plugin -f # force

Writing a Plugin

Plugins export a default object with the following structure:

import { definePlugin } from 'opencode-ai/sdk';

export default definePlugin({
name: 'my-plugin',
version: '1.0.0',
description: 'Description of what this plugin does',

tools: [
// Custom tool definitions
],

hooks: {
'tool.execute.before': async ({ tool, args, session }) => {
// Runs before every tool execution
console.log(`Executing ${tool.name}`);
return args; // optionally modify args
},

'tool.execute.after': async ({ tool, args, result, session }) => {
// Runs after every tool execution
console.log(`Completed ${tool.name}`);
return result; // optionally modify result
},

'session.create': async ({ session }) => {
// Runs when a new session is created
},

'message.send.before': async ({ message, session }) => {
// Runs before a message is sent to the model
return message;
},

'message.send.after': async ({ message, response, session }) => {
// Runs after a model response is received
}
}
});

Hook Reference

HookTimingPayload
tool.execute.beforeBefore a tool runs{ tool, args, session }
tool.execute.afterAfter a tool completes{ tool, args, result, session }
session.createNew session created{ session }
message.send.beforeMessage sent to model{ message, session }
message.send.afterResponse received from model{ message, response, session }

Example: Helicone Session Plugin

The opencode-helicone-session plugin integrates OpenCode with Helicone for observability, logging, and analytics:

opencode plugin opencode-helicone-session

After installation, configure the Helicone API key:

export HELICONE_API_KEY="sk-helicone-..."

The plugin automatically wraps all LLM calls with Helicone session tracking, providing request/response logging, latency monitoring, and cost analysis through the Helicone dashboard.

Example: GitLab Plugin

A GitLab integration plugin might provide tools for repository operations:

export default definePlugin({
name: 'gitlab-tools',
version: '1.0.0',
tools: [
tool({
name: 'gitlab_create_merge_request',
description: 'Create a merge request on GitLab',
parameters: {
type: 'object',
properties: {
projectId: { type: 'string' },
title: { type: 'string' },
sourceBranch: { type: 'string' },
targetBranch: { type: 'string' }
}
},
execute: async (args) => {
const res = await fetch(
`https://gitlab.com/api/v4/projects/${args.projectId}/merge_requests`,
{
method: 'POST',
headers: {
'PRIVATE-TOKEN': process.env.GITLAB_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: args.title,
source_branch: args.sourceBranch,
target_branch: args.targetBranch
})
}
);
return res.json();
}
})
]
});

Plugin Resolution Order

When multiple plugins register the same hook or tool, they execute in this order:

  1. Built-in plugins (OpenCode internal)
  2. npm package plugins (in order listed in plugin array)
  3. .opencode/plugins/ local files (alphabetical)
  4. ~/.config/opencode/plugins/ global files (alphabetical)

Best Practices

  • Name uniquely: Prefix plugin namespaces (e.g., @org/plugin-name) to avoid conflicts.
  • Version strictly: Pin plugin versions in production to prevent unexpected behavior from updates.
  • Minimize hooks: Only use hooks you need. Each hook adds overhead to every matching operation.
  • Fail gracefully: Plugins should catch errors internally and log rather than crash the host process.
  • Document tools: Provide clear descriptions and parameter schemas so the AI agent uses tools correctly.
  • Test locally: Use .opencode/plugins/ during development, then publish to npm for team-wide distribution.