Event-driven callbacks that let plugins react to what OpenCode does.
A hook is a function that runs automatically when a specific event happens inside OpenCode. Instead of polling for changes or manually triggering actions, you subscribe to events like "file edited" or "tool executed" and your code runs at exactly the right moment.
In OpenCode, hooks are objects returned by a plugin's main function. Each key in the object is an event name, and each value is a callback function. When OpenCode emits that event, your callback runs.
For example, a plugin might return a hooks object with a "tool.execute.after" key. Every time any tool finishes running, your function is called with the tool's result. You can inspect it, log it, or even modify the output before it reaches the LLM.
tool.execute.before let you intercept and modify data mid-pipeline.A hook object is just key-value pairs. The key is the event name; the value is an async function.
return {
hooks: {
"file.edited": async (event) => {
console.log("File changed:", event.path);
},
"tool.execute.after": async (event) => {
// inspect the result after the tool ran
console.log("Tool:", event.tool, "Result length:", event.result.length);
},
},
};
Available event categories include:
tool.execute.before, tool.execute.afterfile.edited, file.watcher.updatedsession.created, session.compacted, session.deleted, session.error, session.idle, session.updatedmessage.part.removed, message.part.updated, message.removed, message.updatedpermission.asked, permission.repliedlsp.client.diagnostics, lsp.updatedcommand.executed, installation.updated, server.connected, todo.updated, shell.env, tui.prompt.append, command.execute, tui.toast.showHooks live inside plugin files. A plugin is a JavaScript or TypeScript module placed in:
.opencode/plugins/ (project-level)~/.config/opencode/plugins/ (global)"plugin" array in opencode.jsonThe plugin's main function returns an object with a hooks key. OpenCode reads that and wires up the event listeners.
Create a file in your plugins directory, export a default function, and return hooks:
// .opencode/plugins/my-hook.ts
export default function myPlugin({ project, client, $, directory, worktree }) {
return {
hooks: {
"session.created": async () => {
console.log("New session started in", directory);
},
},
};
}
Restart OpenCode (or reload) and the hook is active.
A plugin that logs every file edit and injects a custom environment variable into the shell:
// .opencode/plugins/log-and-env.ts
export default function({ directory }) {
return {
hooks: {
"file.edited": async (event) => {
console.log(`[edit] ${event.path}`);
},
"shell.env": async () => {
return { MY_VAR: "hello from hook" };
},
},
};
}
experimental.session.compacting?