Saltearse al contenido

Plugins

Escribir plugins propios para extender OpenCode.

Los plugins te permiten extender OpenCode enganchándote a distintos eventos y personalizando su comportamiento. Puedes crear plugins para añadir funcionalidades, integrarte con servicios externos o modificar el comportamiento por defecto.

Para ejemplos, consulta los plugins de la comunidad.


Usar un plugin

Hay dos maneras de cargar plugins.


Desde archivos locales

Coloca archivos JavaScript o TypeScript en el directorio de plugins:

  • .opencode/plugin/ – plugins a nivel de proyecto
  • ~/.config/opencode/plugin/ – plugins globales

Los archivos en estos directorios se cargan automáticamente al inicio.


Desde npm

Declara paquetes npm en tu archivo de configuración:

opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"]
}

Se admiten paquetes normales y con scope.

Puedes explorar plugins disponibles en la sección ecosistema.


Cómo se instalan los plugins

  • Los plugins npm se instalan automáticamente con Bun al inicio. Los paquetes y sus dependencias se cachean en ~/.cache/opencode/node_modules/.
  • Los plugins locales se cargan directamente desde el directorio de plugins. Si necesitan dependencias externas, crea un package.json dentro de tu directorio de configuración (ver Dependencias) o publícalos en npm y añádelos a tu config.

Orden de carga

Los plugins se cargan desde todas las fuentes y sus hooks se ejecutan en secuencia. El orden es:

  1. Config global (~/.config/opencode/opencode.json)
  2. Config del proyecto (opencode.json)
  3. Directorio global de plugins (~/.config/opencode/plugin/)
  4. Directorio de plugins del proyecto (.opencode/plugin/)

Los paquetes npm duplicados con el mismo nombre y versión se cargan una sola vez. En cambio, un plugin local y uno npm con nombres parecidos se cargan por separado.


Crear un plugin

Un plugin es un módulo JavaScript/TypeScript que exporta una o más funciones de plugin. Cada función recibe un objeto de contexto y devuelve un objeto de hooks.


Dependencias

Los plugins locales y las herramientas personalizadas pueden usar dependencias npm externas. Añade un package.json a tu directorio de configuración:

.opencode/package.json
{
"dependencies": {
"shescape": "^2.1.0"
}
}

OpenCode ejecutará bun install al inicio para instalarlas. Después podrás importarlas desde tus plugins y tools.

.opencode/plugin/my-plugin.ts
import { escape } from "shescape"
export const MyPlugin = async (ctx) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "bash") {
output.args.command = escape(output.args.command)
}
},
}
}

Estructura básica

.opencode/plugin/example.js
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
console.log("Plugin initialized!")
return {
// Implementaciones de hooks aquí
}
}

El plugin recibe:

  • project: información del proyecto actual.
  • directory: directorio de trabajo actual.
  • worktree: ruta del worktree de Git.
  • client: cliente SDK de OpenCode para hablar con el servidor.
  • $: API de shell de Bun (shell API) para ejecutar comandos.

Soporte TypeScript

Para plugins en TypeScript puedes importar tipos del paquete de plugins:

my-plugin.ts
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
// Implementaciones tipadas de hooks
}
}

Eventos

Los plugins pueden suscribirse a eventos (ver ejemplos más abajo). Lista de eventos disponibles:

Eventos de comando

  • command.executed

Eventos de archivo

  • file.edited
  • file.watcher.updated

Eventos de instalación

  • installation.updated

Eventos LSP

  • lsp.client.diagnostics
  • lsp.updated

Eventos de mensaje

  • message.part.removed
  • message.part.updated
  • message.removed
  • message.updated

Eventos de permisos

  • permission.replied
  • permission.updated

Eventos de servidor

  • server.connected

Eventos de sesión

  • session.created
  • session.compacted
  • session.deleted
  • session.diff
  • session.error
  • session.idle
  • session.status
  • session.updated

Eventos de TODO

  • todo.updated

Eventos de herramienta

  • tool.execute.after
  • tool.execute.before

Eventos de TUI

  • tui.prompt.append
  • tui.command.execute
  • tui.toast.show

Ejemplos

Algunos ejemplos de plugins para extender OpenCode.


Notificaciones

Enviar notificaciones cuando ocurren ciertos eventos:

.opencode/plugin/notification.js
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
return {
event: async ({ event }) => {
// Notificar al completar una sesión
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
}
},
}
}

Aquí usamos osascript para ejecutar AppleScript en macOS y mostrar notificaciones.


Protección de .env

Evitar que OpenCode lea archivos .env:

.opencode/plugin/env-protection.js
export const EnvProtection = async ({ project, client, $, directory, worktree }) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Do not read .env files")
}
},
}
}

Herramientas personalizadas

Los plugins también pueden registrar herramientas personalizadas:

.opencode/plugin/custom-tools.ts
import { type Plugin, tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
mytool: tool({
description: "This is a custom tool",
args: {
foo: tool.schema.string(),
},
async execute(args, ctx) {
return `Hello ${args.foo}!`
},
}),
},
}
}

El helper tool crea una herramienta que OpenCode puede invocar. Acepta un esquema Zod y devuelve una definición con:

  • description: qué hace la herramienta;
  • args: esquema de argumentos;
  • execute: función que se ejecuta cuando se llama a la herramienta.

Tus herramientas personalizadas se exponen junto a las herramientas integradas.


Logging estructurado

Usa client.app.log() en lugar de console.log para logs estructurados:

.opencode/plugin/my-plugin.ts
export const MyPlugin = async ({ client }) => {
await client.app.log({
service: "my-plugin",
level: "info",
message: "Plugin initialized",
extra: { foo: "bar" },
})
}

Niveles: debug, info, warn, error. Consulta la documentación del SDK para más detalles.


Hooks de compactación

Personalizar el contexto incluido cuando se compacta una sesión:

.opencode/plugin/compaction.ts
import type { Plugin } from "@opencode-ai/plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// Inyectar contexto adicional en el prompt de compactación
output.context.push(`
## Custom Context
Include any state that should persist across compaction:
- Current task status
- Important decisions made
- Files being actively worked on
`)
},
}
}

El hook experimental.session.compacting se ejecuta antes de que el modelo genere el resumen de continuación. Úsalo para inyectar contexto de dominio que el prompt por defecto no capturaría.

También puedes sustituir por completo el prompt de compactación asignando output.prompt:

.opencode/plugin/custom-compaction.ts
import type { Plugin } from "@opencode-ai/plugin"
export const CustomCompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// Reemplazar todo el prompt de compactación
output.prompt = `
You are generating a continuation prompt for a multi-agent swarm session.
Summarize:
1. The current task and its status
2. Which files are being modified and by whom
3. Any blockers or dependencies between agents
4. The next steps to complete the work
Format as a structured prompt that a new agent can use to resume work.
`
},
}
}

Si se define output.prompt, se ignora output.context y se usa solo el prompt personalizado.