Org in a Box
Architecture

Plugin System

How opencode plugins work and how to extend Org in a Box with your own.

Overview

Org in a Box extends opencode via the @opencode-ai/plugin SDK. Each plugin is a TypeScript module that exports a Plugin function — opencode calls it on startup and registers the returned hooks.

Bundled Plugins

PluginPackageKey Hooks / Tools
plugin-memorypackages/plugins/memorychat.message, system.transform, memory tool
plugin-permissionspackages/plugins/permissionspermission.asked → auto-approve/deny
plugin-analyticspackages/plugins/analyticstool.execute.after → usage_events
plugin-session-searchpackages/plugins/session-searchsession_search tool
plugin-subagentpackages/plugins/subagentsubagent tool (creates child sessions)
plugin-tunnel-toolspackages/plugins/tunnel-toolstunnel_connect, tunnel_disconnect
plugin-host-toolspackages/plugins/host-toolspython_exec, email/calendar stubs
plugin-orchestratorpackages/plugins/orchestratorplan_tasks, plan_status tools
plugin-reflectionpackages/plugins/reflectionsession.status → trajectory + skill proposal
plugin-browserpackages/plugins/browserbrowser_navigate, browser_click, etc.
plugin-skill-autowritepackages/plugins/skill-autowriteAuto-writes promoted skills to SKILL.md
plugin-claude-oauthpackages/plugins/claude-oauthClaude.ai OAuth credential management

Plugin Structure

import type { Plugin, Hooks } from "@opencode-ai/plugin"

export const plugin: Plugin = async (input, options) => {
  // initialization (DB connections, config, etc.)
  
  const hooks: Hooks = {
    // Hook handlers
    "chat.message": async (ctx, message) => { /* … */ },
    "experimental.chat.system.transform": async (ctx, out) => {
      out.system.push("Your custom system prompt content")
    },
    // Tool definitions
    tool: {
      my_tool: tool({
        description: "…",
        args: { query: z.string() },
        async execute(args, ctx) {
          return `result: ${args.query}`
        },
      }),
    },
  }
  
  return hooks
}

export default plugin

Available Hooks

HookWhen It FiresInputOutput
chat.messageEvery messagectx, messagevoid
tool.execute.afterAfter every tool call{ tool, input, output, sessionID }void
session.statusSession status changes{ sessionID, status }void
experimental.chat.system.transformBefore every turn{ sessionID, model }{ system: string[] }
experimental.session.compactingBefore compaction{ sessionID }{ context: string[], prompt?: string }
experimental.compaction.autocontinueDuring compaction{ sessionID }{ enabled: boolean }
permission.askedPermission request{ sessionID, tool, permission }void

Registering Plugins

Edit config/opencode.jsonc:

{
  "plugin": [
    "@orginabox/plugin-memory",
    "@orginabox/plugin-orchestrator",
    "./path/to/my-custom-plugin"
  ]
}

Writing a Custom Plugin

  1. Create a new package in packages/plugins/my-plugin/
  2. Add package.json with "main": "src/index.ts" and dep on @opencode-ai/plugin
  3. Export a plugin: Plugin function
  4. Add the package to the root workspace in package.json
  5. Add the package name to config/opencode.jsonc

On this page