Creating OpenCode Plugins
<critical>
Re-read this file periodically during plugin development to refresh context and ensure you're following the correct procedure.
</critical>
<workflow>
Procedure Overview
| Step | Action | Read |
|---|
| 1 | Verify SDK reference | Run extract script |
| 2 | Validate feasibility | This file |
| 3 | Design plugin | , references/hook-patterns.md
, |
| 4 | Implement | references/tool-helper.md
(if custom tools) |
| 5 | Add UI feedback | references/toast-notifications.md
, references/ui-feedback.md
(if needed) |
| 6 | Test | |
| 7 | Publish | , references/update-notifications.md
(if npm) |
Step 1: Verify SDK Reference (REQUIRED)
Before creating any plugin, MUST regenerate the API reference to ensure accuracy:
bash
bun run .opencode/skill/create-opencode-plugin/scripts/extract-plugin-api.ts
This generates:
- - All available hooks and signatures
- - All event types and properties
references/tool-helper.md
- Tool creation patterns
Step 2: Validate Feasibility (REQUIRED)
MUST determine if the user's concept is achievable with available hooks.
Feasible as plugins:
- Intercepting/blocking tool calls
- Reacting to events (file edits, session completion, etc.)
- Adding custom tools for the LLM
- Modifying LLM parameters (temperature, etc.)
- Custom auth flows for providers
- Customizing session compaction
- Displaying status messages (toasts, inline)
NOT feasible (inform user):
- Modifying TUI rendering or layout
- Adding new built-in tools (requires OC source)
- Changing core agent behavior/prompts
- Intercepting assistant responses mid-stream
- Adding new keybinds or commands
- Modifying internal file read/write
- Adding new permission types
If not feasible, MUST inform user clearly. Suggest:
- OC core changes: contribute to
- MCP tools: use MCP server configuration
- Simple automation: use shell scripts
Step 3: Design Plugin
READ:
for available hooks,
references/hook-patterns.md
for implementation patterns.
READ:
for code architecture principles. MUST follow these design guidelines:
- Modular structure: Split complex plugins into multiple focused files (types, utilities, hooks, tools)
- Single purpose: Each function does ONE thing well
- DRY: Extract common patterns into shared utilities immediately
- Small files: Keep individual files under 150 lines - split into smaller modules as needed
- No monoliths: MUST NOT put all plugin code in a single file
Plugin Locations
| Scope | Path | Use Case |
|---|
| Project | .opencode/plugin/<name>/index.ts
| Team-shared, repo-specific |
| Global | ~/.config/opencode/plugin/<name>/index.ts
| Personal, all projects |
Basic Structure
typescript
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
// Setup code runs once on load
return {
// Hook implementations - see references/hook-patterns.md
}
}
Context Parameters
| Parameter | Type | Description |
|---|
| | Current project info (id, worktree, name) |
| SDK Client | OpenCode API client |
| | Bun shell for commands |
| | Current working directory |
| | Git worktree path |
Step 4: Implement
READ:
references/hook-patterns.md
for hook implementation examples.
READ:
references/tool-helper.md
if adding custom tools (Zod schemas).
READ:
if using event hook (event types/properties).
READ:
for complete plugin examples.
ALWAYS READ:
and follow modular design principles.
Plugin Structure (Non-Monolithic)
For complex plugins, MUST use a modular directory structure:
.opencode/plugin/my-plugin/
├── index.ts # Entry point, exports Plugin
├── types.ts # TypeScript types/interfaces
├── utils.ts # Shared utilities
├── hooks/ # Hook implementations
│ ├── event.ts
│ └── tool-execute.ts
└── tools/ # Custom tool definitions
└── my-tool.ts
Example modular index.ts:
typescript
import type { Plugin } from "@opencode-ai/plugin"
import { eventHooks } from "./hooks/event"
import { toolHooks } from "./hooks/tool-execute"
import { customTools } from "./tools"
export const MyPlugin: Plugin = async ({ project, client }) => {
return {
...eventHooks({ client }),
...toolHooks({ client }),
tool: customTools,
}
}
Keep each file under 150 lines. Split as complexity grows.
Common Mistakes
| Mistake | Fix |
|---|
| Using | Use tool: { name: tool({...}) }
|
| Wrong event property names | Check |
| Sync event handler | MUST use |
| Not throwing to block | in |
| Forgetting TypeScript types | import type { Plugin } from "@opencode-ai/plugin"
|
Step 5: Add UI Feedback (Optional)
Only if plugin needs user-visible notifications:
READ:
references/toast-notifications.md
for transient alerts (brief popups)
READ:
references/ui-feedback.md
for persistent inline status messages
Choose based on:
| Need | Use |
|---|
| Brief alerts, warnings | Toast |
| Detailed stats, multi-line | Inline message |
| Config validation errors | Toast |
| Session completion notice | Toast or inline |
Step 6: Test
READ:
for full testing procedure.
Quick Test Steps
-
Create test folder with
:
jsonc
{
"plugin": ["file:///path/to/your/plugin/index.ts"],
}
-
Verify plugin loads:
bash
cd /path/to/test-folder
opencode run hi
-
Test interactively:
-
SHOULD recommend specific tests based on hook type used.
Step 7: Publish (Optional)
READ:
for npm publishing.
READ:
references/update-notifications.md
for version update toasts (for users with pinned versions).
</workflow>
<reference_summary>
Reference Files Summary
| File | Purpose | When to Read |
|---|
| Hook signatures (auto-generated) | Step 3-4 |
| Event types (auto-generated) | Step 4 (if using events) |
| Zod tool schemas (auto-generated) | Step 4 (if custom tools) |
| Hook implementation examples | Step 3-4 |
| Code architecture principles | Step 3 (Design) |
| Complete plugin examples | Step 4 |
| Toast popup API | Step 5 (if toasts needed) |
| Inline message API | Step 5 (if inline needed) |
| Testing procedure | Step 6 |
| npm publishing | Step 7 |
| Version toast pattern | Step 7 (for npm plugins) |
</reference_summary>