Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
Christopher Boone avatar

Notify

  • 2 repo stars
  • Updated July 24, 2026
  • cboone/agent-harness-plugins

Get a macOS notification when Claude Code, OpenCode, or Codex CLI finishes a task or needs your attention.

About

Notify sends macOS desktop notifications when an AI coding agent — Claude Code, OpenCode, or Codex CLI — finishes a task or pauses needing input. It lets a developer step away from a long-running agent session and get pinged the moment it completes or stalls. A small workflow/alerting utility for agent-driven development.

  • macOS desktop notifications
  • Works with Claude Code, OpenCode, Codex
  • Fires on task completion
  • Alerts when attention needed

Notify by the numbers

  • Data as of Jul 25, 2026 (Skillselion catalog sync)
/plugin marketplace add cboone/agent-harness-plugins
/plugin install notify@agent-harness-plugins

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
repo stars2
Last updatedJuly 24, 2026
Repositorycboone/agent-harness-plugins

What it does

Get a macOS notification when Claude Code, OpenCode, or Codex CLI finishes a task or needs your attention.

README.md

Notify (macOS)

Sends rich, harness-aware macOS notifications when Claude Code, OpenCode, or Codex CLI finishes a task or needs your attention. Click a notification to focus the originating terminal app and tmux pane.

Type: Hook Requires: alerter (>= 26.5). Install via Homebrew: brew install vjeantet/tap/alerter. Also requires jq and macOS tmux (only used when running inside a tmux session).

Installation

Claude Code

See the marketplace install instructions.

Using with Codex CLI

codex plugin marketplace add cboone/agent-harness-plugins

Enable plugin-bundled hooks once per host so the Stop hook fires:

codex features enable plugin_hooks

Without this flag the plugin installs successfully but the hook is silently ignored. See Codex CLI known limitations for context.

Refresh the marketplace after repository updates:

codex plugin marketplace upgrade agent-harness-plugins

Codex's hook event enum does not include Notification or PreCompact, so the plugin only wires the Stop event on Codex. PermissionRequest is intentionally not wired: that hook runs in the automatic-policy path before Codex's user approval UI is shown, not as a user-facing prompt, so notifying on it would alert the human about decisions Codex's internal approver is already making. For idle / elicitation / compact-style banners and approval prompts, enable Codex's native tui.notifications = true in ~/.codex/config.toml (the two are complementary; both can run at once).

Using with OpenCode

OpenCode loads the plugin automatically when OPENCODE_CONFIG_DIR is set to this repository's dist/opencode/ mirror. The TypeScript plugin lives at opencode/index.ts and dispatches on OpenCode's event stream rather than Claude Code's named matchers.

OpenCode's event model differs from Claude Code's, so the parity is approximate:

OpenCode event Notification Claude Code equivalent
session.idle Task completed Stop (with project + branch + last user/assistant turn)
permission.updated "Needs permission…" Notification (permission_prompt, elicitation_dialog)
experimental.session.compacting "Auto-compacting…" PreCompact (auto)

The standalone "Waiting for input…" notification (Claude Code's Notification:idle_prompt) is not separately representable: OpenCode's session.idle already carries the Stop semantics. The compacting hook depends on an experimental OpenCode API and may break on upgrades.

Granting notification permission

alerter posts notifications by impersonating Terminal's bundle identity (the v26.4+ default) so it appears under "Terminal" in System Settings → Notifications, where you grant alert permission once. You will not see a separate "alerter" entry. The first notification after install may not appear until permission is granted; the second will.

What it does

Delivers native macOS notifications so you can work in other apps while an agent runs. Each notification carries:

  • A per-harness icon: Claude Code, OpenCode, or Codex's app icon.
  • A subtitle that identifies the task: when running inside tmux with a custom pane title (set by workmux or similar), the subtitle is <project> · <pane title>. Otherwise, <project> · <branch suffix>, where the branch suffix is everything after the first / (so feature/improve-notifier becomes improve-notifier).
  • An informative body: per-event content (see matrix below). Claude Code permission events show a per-tool preview (the Bash command, the file path being edited, etc.) reconstructed from the most recent tool_use block in the transcript, since the Notification payload itself omits tool details. OpenCode permission events use OpenCode's pre-computed title, falling back to pattern or per-tool metadata. Claude Code and OpenCode Stop events show <last user message> → <last assistant message tail>; the Claude Code assistant tail comes from the Stop payload's last_assistant_message rather than from a transcript walk. Codex Stop is the last assistant message alone, also taken from the payload.
  • A per-event sound (Tink for Claude Code idle/elicit and Codex done, Funk for permission and OpenCode error, Pop for auto-compact, Glass for Claude Code and OpenCode done). Codex Stop uses the soft Tink rather than the louder Glass because Codex fires Stop once per "no follow-up needed" sampling cycle in its turn loop, so a single user turn can produce multiple notifications when Stop hooks request continuation. Each Stop updates the same notification group, so successive firings replace the previous banner in place rather than stacking.
  • A per-event group so a fresh notification dismisses any prior notification of the same kind, instead of stacking.
  • Click-to-focus: clicking the body of any notification activates the originating terminal app (auto-detected from $TERM_PROGRAM, supports Apple Terminal, iTerm2, Ghostty, WezTerm, VSCode, Alacritty) and, if you were inside tmux when the hook fired, switches the tmux client to the originating session, window, and pane.

When it fires

Claude Code

Event Title Body Sound
Notification:idle_prompt Claude Code · Idle Last assistant message tail (fallback Waiting for input) Tink
Notification:elicitation_dialog Claude Code · Question The actual question text from the payload Tink
Notification:permission_prompt Claude Code · Permission <Tool>: <preview> (subtitle is suffixed with the tool) Funk
PreCompact:auto Claude Code · Compacting Auto-compacting context Pop
Stop Claude Code · Done <last user message> → <last assistant message tail> Glass

Codex

Event Title Body Sound
Stop Codex · Done last_assistant_message from the payload Tink

Codex fires Stop once per "no follow-up needed" sampling cycle in its turn loop (codex-rs/core/src/session/turn.rs), so a single user turn may produce multiple Stop notifications when Stop hooks request continuation. The notification uses the soft Tink sound and reuses the codex-stop group, so successive firings within one turn dismiss the prior banner rather than stacking. Click the body to focus the originating pane.

OpenCode

Event Title Body Sound
permission.updated OpenCode · Permission OpenCode's pre-computed title, falling back to pattern or per-tool metadata Funk
session.error OpenCode · Error error.data.message (or the error name) Funk
experimental.session.compacting OpenCode · Compacting Auto-compacting context Pop
session.idle OpenCode · Done <last user message> → <last assistant message tail> Glass

Click-to-focus details

When you click the body of a notification, the plugin runs scripts/focus-pane with the captured terminal program and tmux state. The script does two things.

Activate the host terminal app via osascript -e 'tell application id "<bundle-id>" to activate'. Bundle IDs are derived from $TERM_PROGRAM:

$TERM_PROGRAM App
Apple_Terminal Terminal.app
iTerm.app iTerm2
ghostty Ghostty
WezTerm WezTerm
vscode VS Code
alacritty Alacritty
(anything else) Terminal.app

Switch the tmux client if the hook fired inside tmux: tmux switch-client -t <session> \; select-window -t <session>:<window> \; select-pane -t <session>:<window>.<pane>.

Failures (closed pane, no client attached, missing terminal app) are silent: clicking a notification should never produce a visible error.

Notes and caveats

  • alerter blocks waiting for user interaction, so every event launches it in a detached subshell. The harness is never held up. Each invocation has a 24-hour timeout to prevent orphaned processes from accumulating.
  • The transcript-based extractors (last user message, last assistant message tail, pending tool use) iterate the transcript JSONL. Performance is fine for typical sessions; very long transcripts may add a small delay before the notification appears.
  • The --app-icon flag uses a private macOS API that alerter keeps working release to release. If a future macOS update breaks it, notifications will still fire but with the default Terminal icon.

See also

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.