Agent skill
opencode-plugins
Install this agent skill to your Project
npx add-skill https://github.com/johnlindquist/script-kit-next/tree/main/.opencode/skill/opencode-plugins
SKILL.md
OpenCode Plugins
Guide for creating OpenCode plugins. Use when building plugins to extend OpenCode with custom hooks, tools, or integrations.
Plugin Location
Plugins are loaded from:
.opencode/plugin/- Project-level (preferred)~/.config/opencode/plugin/- Global
Basic Structure
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
// project: Current project information
// client: OpenCode SDK client for AI interaction
// $: Bun shell API for executing commands
// directory: Current working directory
// worktree: Git worktree path
return {
// Hook implementations
}
}
Available Hooks
Core Hooks
| Hook | Signature | Purpose |
|---|---|---|
event |
(input: { event: Event }) => Promise<void> |
Generic event handler for all events |
config |
(input: Config) => Promise<void> |
Modify configuration |
tool |
{ [key: string]: ToolDefinition } |
Register custom tools |
auth |
AuthHook |
Custom authentication providers |
Chat Hooks
| Hook | Signature | Purpose |
|---|---|---|
chat.message |
(input, output: { message: UserMessage; parts: Part[] }) => Promise<void> |
Modify user messages before sending |
chat.params |
(input, output: { temperature, topP, topK, options }) => Promise<void> |
Modify LLM parameters |
Tool Execution Hooks
| Hook | Signature | Purpose |
|---|---|---|
tool.execute.before |
(input: { tool, sessionID, callID }, output: { args }) => Promise<void> |
Intercept before tool runs |
tool.execute.after |
(input: { tool, sessionID, callID }, output: { title, output, metadata }) => Promise<void> |
Process after tool completes |
Permission Hooks
| Hook | Signature | Purpose |
|---|---|---|
permission.ask |
(input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void> |
Auto-approve/deny permissions |
Experimental Hooks
| Hook | Signature | Purpose |
|---|---|---|
experimental.chat.system.transform |
(input: {}, output: { system: string[] }) => Promise<void> |
Modify system prompt |
experimental.chat.messages.transform |
(input: {}, output: { messages }) => Promise<void> |
Transform message history |
experimental.session.compacting |
(input: { sessionID }, output: { context: string[]; prompt?: string }) => Promise<void> |
Add context during compaction |
experimental.text.complete |
(input: { sessionID, messageID, partID }, output: { text }) => Promise<void> |
Text completion |
Common Patterns
Inject Context into System Prompt
Best for project-specific reminders that should appear in every conversation:
export const ContextPlugin: Plugin = async () => {
const REMINDER = `
## Project Guidelines
- Always run tests before committing
- Use TypeScript strict mode
`.trim()
return {
"experimental.chat.system.transform": async (_input, output) => {
output.system.push(REMINDER)
}
}
}
Preserve Context During Compaction
Ensures important context survives session compaction:
export const CompactionPlugin: Plugin = async () => {
return {
"experimental.session.compacting": async (_input, output) => {
output.context.push("## Critical Context\n- Key fact 1\n- Key fact 2")
}
}
}
Custom Compaction Prompt
Replace the default compaction prompt entirely:
export const CustomCompactionPlugin: Plugin = async () => {
return {
"experimental.session.compacting": async (_input, output) => {
output.prompt = `You are summarizing a coding session.
Focus on: current task, files modified, next steps.`
}
}
}
Protect Sensitive Files
Prevent reading .env or other sensitive files:
export const EnvProtection: Plugin = async () => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath?.includes(".env")) {
throw new Error("Reading .env files is not allowed")
}
}
}
}
Send Notifications
Use macOS notifications for session events:
export const NotificationPlugin: Plugin = async ({ $ }) => {
return {
event: async ({ event }) => {
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Done!" with title "OpenCode"'`
}
}
}
}
Custom Tools
Add project-specific tools:
import { tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async () => {
return {
tool: {
myTool: tool({
description: "Does something useful",
args: {
input: tool.schema.string(),
count: tool.schema.number().optional(),
},
async execute(args, ctx) {
return `Processed: ${args.input} (count: ${args.count ?? 1})`
},
}),
},
}
}
Event Types
Available events for the event hook:
Session Events
session.created- New session startedsession.compacted- Session was compactedsession.deleted- Session deletedsession.diff- Changes detectedsession.error- Error occurredsession.idle- Session became idlesession.status- Status changedsession.updated- Session updated
Message Events
message.updated- Message changedmessage.removed- Message deletedmessage.part.updated- Part of message changedmessage.part.removed- Part of message deleted
File Events
file.edited- File was editedfile.watcher.updated- File watcher detected change
Other Events
command.executed- Command raninstallation.updated- Installation changedlsp.client.diagnostics- LSP diagnostics receivedlsp.updated- LSP state changedpermission.replied- Permission answeredpermission.updated- Permission changedserver.connected- Server connectedtodo.updated- Todo list changedtool.execute.after- Tool finishedtool.execute.before- Tool starting
Package Setup
For TypeScript support, ensure .opencode/package.json has:
{
"dependencies": {
"@opencode-ai/plugin": "^1.0.203"
}
}
Then run bun install in the .opencode/ directory.
Best Practices
- Use TypeScript - Get type safety and better IDE support
- Keep plugins focused - One plugin per concern
- Use experimental hooks carefully - They may change
- Test locally first - Plugins run on every session
- Don't block - Hooks should be fast; use async for slow operations
- Handle errors gracefully - Throwing stops the hook chain
Reference
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
Generate Component Documentation
Based on existing docs styles and specific API implementations, and referencing same name stories, generate comprehensive documentation for the new component.
Generate Component Story
Generate a comprehensive story for a new component for as example.
new-component
How to write a new component of GPUI Component.
troubleshooting
Diagnose and fix common Script Kit issues. Use when the user reports bugs, crashes, missing features, or unexpected behavior in Script Kit GPUI.
script-authoring
Create and manage TypeScript scripts for Script Kit. Use when the user wants to write a new script, edit an existing script, or understand Script Kit's SDK and metadata system.
agents
Create mdflow-backed agent files for Script Kit. Use when the user wants to create AI agents, configure agent backends (Claude, Gemini, Codex), or manage agent metadata.
Didn't find tool you were looking for?