Skip to content

Instantly share code, notes, and snippets.

@matiasmasca
Created May 3, 2026 00:16
Show Gist options
  • Select an option

  • Save matiasmasca/30175c93519fd96b469c52758d24cad7 to your computer and use it in GitHub Desktop.

Select an option

Save matiasmasca/30175c93519fd96b469c52758d24cad7 to your computer and use it in GitHub Desktop.
Desktop notification for OpenCode on Linux and MacOS
/*
* Desktop notification for OpenCode Agent
* for Linux and MacOs
*
* Fox Linux, you will need notify-send and spd-say
* notify-send utility is available on all the major Linux distributions as part of the libnotify library
* spd-say is a command-line client for Speech Dispatcher that converts text to speech.
*
* For MacOs, you will need ´osascript´ and ´say´
* osacript: it is a command-line invoked application that can run AppleScripts and JavaScript for Automation scripts
* say command: it has been included in macOS since the early days of Mac OS X, building on Apple's text-to-speech technology
// base on the work of Michael Faisst on https://michael.faisst.io/blog/proper-opencode-notifications
*/
import { Plugin } from "@opencode-ai/plugin";
export const NotificationPlugin: Plugin = async ({ $ }) => {
// const notificationSound = "~/.config/opencode/plugin/notification.mp3";
const mainSessions = new Set<string>();
const playNotification = async (
message: string,
title: string = "OpenCode"
) => {
const platform = process.platform;
try {
if (platform === 'darwin') {
// macOS: notification via osascript, TTS via say
await $`osascript -e 'display notification "${message}" with title "${title}"'`.catch(() => {});
await $`say "${message}"`.catch(() => {});
} else if (platform === 'linux') {
// Linux: fix notify-send argument order and spd-say typo
await $`notify-send --urgency=low "${title}" "${message}"`.catch(() => {});
await $`spd-say -w "${message}" -l en`.catch(() => {});
} else {
console.warn(`Notification plugin: Unsupported platform ${platform}`);
}
} catch {
// Ignore errors to prevent plugin crashes
}
};
return {
event: async ({ event }) => {
// Track main sessions (sessions without a parent)
if (event.type === "session.created") {
const session = event.properties.info;
if (!session.parentID) {
mainSessions.add(session.id);
}
}
// Clean up tracked sessions when deleted
if (event.type === "session.deleted") {
mainSessions.delete(event.properties.info.id);
}
// Notify when main session becomes idle (not subagents)
if (event.type === "session.status") {
const { sessionID, status } = event.properties;
if (status.type === "idle" && mainSessions.has(sessionID)) {
await playNotification("Task completed!", "OpenCode");
}
}
// Notify when a question is asked
if (event.type === "question.asked") {
await playNotification(
"Question waiting for your input",
"OpenCode"
);
}
// Notify when permission is requested
if (event.type === "permission.asked") {
await playNotification("Permission required", "OpenCode");
}
}
};
};
// Create a package.json in your OpenCode plugin directory (~/.config/opencode/package.json) if you don't have one already, and add the plugin SDK as a dependency:
{
"dependencies": {
"@opencode-ai/plugin": "1.1.28"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment