omp packages

agent-notify0.18.1

Get notified the moment your AI coding agent needs you — Claude Code, Codex, OMP/oh-my-pi, ZCode & Grok → phone & desktop (Feishu, WeCom, DingTalk, Bark, ntfy, Slack).

bigox Published 12 days ago MIT ~829 downloads/mo

Built for omp

The author tagged this package oh-my-pi.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

Agent Notify

Agent Notify

Notifies you when your agent needs you

Go Version License: MIT Release

English | 简体中文

Overview

Agent Notify hooks into the lifecycle events of AI coding agents (Claude Code, Codex, OpenCode, ZCode, Grok, Droid, OMP/oh-my-pi, DeepSeek Harness, etc.) and pushes them to your phone and desktop. Get notified the moment your agent needs permission, finishes a task, or fails — so you never have to babysit a running agent.

Supported delivery channels: OS-native system notifications, Feishu/Lark, WeChat Work (企业微信), DingTalk (钉钉), Bark (iOS), and ntfy.

Agent Notify demo

Quick Start

Run it without installing anything:

npx agent-notify@latest

Or install it globally, which puts the agent-notify command on your PATH:

npm install -g agent-notify
agent-notify

Update a global install later:

npm update -g agent-notify

Both routes run the same launcher: it downloads the platform binary into ~/.agent-notify/ on first run, so the npm package itself is only a bootstrap. The launcher updates the binary to the version of the npm package it was invoked from, never to whatever is newest — so keep that package current: npx agent-notify@latest re-resolves from the registry on every run, while a global install only moves when you run npm update -g agent-notify. The global install is the better fit if you plan to call agent-notify directly — agent-notify doctor, agent-notify send, agent-notify freeze — rather than going through npx every time. Pin a version with npm install -g agent-notify@0.17.0.

You can also send a custom message directly through a configured channel:

agent-notify send --channel wechat-work --agent omp "Deployment finished; please check the service"
agent-notify send --channel ntfy --agent omp --title "Build result" --message "Build succeeded"

send reads the selected agent's channel configuration and sends explicitly, regardless of that channel's enabled flag or event subscription list. Supported channels are system, feishu, wechat, wechat-work, dingtalk, bark, ntfy, and slack.

Features

Supported Channels

Channel Description Setup
🖥️ System Notification Native notifications on macOS, Linux, and Windows Default
Feishu / Lark One-click QR-code binding; push via Feishu bot messages QR scan
WeChat Work Push notifications via a WeChat Work group bot webhook Webhook
DingTalk Push notifications via a DingTalk group bot webhook Webhook
Bark Push to iOS devices via a Bark webhook URL Webhook
ntfy Push via ntfy.sh or self-hosted ntfy server Topic
Slack Push via Slack Incoming Webhook Webhook
Discord Push via Discord channel webhook 🚧 Webhook
Telegram Push via Telegram Bot API 🚧 Bot token

Supported Events

Event Claude Code Codex OpenCode ZCode Grok Droid OMP DSH
permission_required ✅ ✅ ✅ ✅ ✅ ✅ ✅* ✅
input_required ✅ — ✅ — ✅ ✅ ✅ ✅
run_completed ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
run_failed ✅ — ✅ ✅ ✅ — ✅ ✅

Notes:

  • Claude Code subscribes via hooks in ~/.claude/settings.json: PermissionRequest, Notification, Stop, PostToolUseFailure, and SessionStart.
  • Codex subscribes via ~/.codex/hooks.json: PermissionRequest and Stop (mapped to permission_required / run_completed), plus SessionStart. input_required and run_failed have no corresponding Codex hook yet, so they are not supported.
  • OpenCode uses a JS plugin instead of native hooks: the plugin is written to ~/.agent-notify/opencode-plugin.js (binary path baked into JS), and its path is registered in ~/.config/opencode/opencode.json (user) or ./opencode.json (project) plugin array. The plugin subscribes to session.created→session_start, permission.asked→permission_required, question.asked→input_required, session.status(idle)→input_required, session.idle→run_completed, session.error→run_failed.
  • ZCode subscribes via ~/.zcode/cli/config.json: SessionStart, PermissionRequest, PostToolUseFailure, and Stop, mapped to permission_required, run_failed, and run_completed. ZCode has no Notification event (so no input_required), and its hook schema is strict — an unknown event name will cause the whole hooks config to be silently dropped.
  • Grok subscribes via ~/.grok/hooks/agent-notify.json: SessionStart, Notification, Stop, StopFailure, and PostToolUseFailure. There is no dedicated PermissionRequest event; Notifications with permission/approval semantics map to permission_required (marked *), others map to input_required. StopFailure / PostToolUseFailure map to run_failed.
  • Droid subscribes via ~/.factory/hooks.json: SessionStart, Notification, Stop, mapped to session_start / permission_required|input_required / run_completed. Droid has no failure event, so run_failed is not supported. session_start is only used for click-to-focus window capture, not as a notification event.
  • OMP uses a native TypeScript extension instead of a JSON command hook: user scope writes ~/.omp/agent/extensions/agent-notify.ts, while project scope writes .omp/extensions/agent-notify.ts. It listens to session_start, tool_approval_requested, tool_execution_start, and session_stop, mapping them to focus capture, permission_required, input_required, and run_completed/run_failed. The ask tool blocks the session waiting for an answer, so its tool_execution_start is mapped to input_required. A run is judged by session_stop's stop reason: stop_reason: "error" (or an aborted stop with an error message) maps to run_failed; ordinary per-tool errors are not treated as run failures. permission_required is emitted only when OMP actually requests tool approval.
  • OMP respects OMP_PROFILE / PI_PROFILE profiles and the PI_CODING_AGENT_DIR override.
  • DeepSeek Harness uses a native Cordis plugin (the separate agent-notify-dsh package) instead of a JSON command hook. The plugin subscribes directly to the harness's lifecycle extension points — agent/created→session_start, approval/request→permission_required, user-questions/request→input_required, agent/turn-stopping→run_completed, agent/error→run_failed — and spawns agent-notify handle-dsh-hook detached, never blocking the agent. Install it with dsh plugin --profile web add agent-notify-dsh. This native route is deliberate: DSH's bundled Claude Code hook bridge only recognises SessionStart and Stop, so PermissionRequest and Notification would be dropped silently, losing the pending-authorization alert that matters most. Only root agents are reported; subagent events are filtered to avoid notification spam.
  • SessionStart does not produce a notification. It is subscribed on every agent solely to capture the terminal window at session start, which powers Linux window-level Click-to-Focus. On macOS/Windows the SessionStart hook is a no-op.

Supported Platforms

Platform Architecture Status
macOS amd64 / arm64 ✅
Linux amd64 / arm64 ✅
Windows amd64 / arm64 ✅

Click-to-Focus

System notifications are clickable — clicking one brings you back to the terminal / window where the agent is running. Behavior differs by platform:

  • macOS — App-level by default (activates the agent's terminal/IDE app). For window-level focus (return to the exact window even when several are open), set AGENT_NOTIFY_FOCUS_PRECISION=window in your login shell environment (e.g. ~/.zshrc); this uses a bundled helper and requires Accessibility permission. Unset stays app-level.
  • Linux (X11) — Window-level. The exact terminal window is captured at session start (via the SessionStart hook) and re-focused on click, so it distinguishes sibling windows of single-process terminals (deepin-terminal, GNOME Terminal, etc.). Native Wayland windows can't be targeted.
  • Windows — Returns to the terminal window via a bundled helper.

AGENT_NOTIFY_FOCUS_PRECISION accepts window (window-level) or app (app-level — the default). Values are case-insensitive and whitespace-trimmed; anything unset or unrecognized falls back to app. This variable only affects macOS — Linux is always window-level, and Windows uses its own helper.

Click-to-focus is enabled by default for the System channel; the target app/window is detected automatically from the hook's environment and process tree.

Configuration

On first run, the launcher downloads the platform-specific binary matching the current npm package version from GitHub Releases and installs it to:

  • macOS / Linux: ~/.agent-notify/agent-notify
  • Windows: ~/.agent-notify/agent-notify.exe

On every subsequent run it checks the local binary version against the version of the npm package the launcher ran from: it downloads if missing, updates if it differs, and otherwise runs directly. Invoke with npx agent-notify@latest (or run npm update -g agent-notify) to move to a new release. The launcher never persistently modifies PATH — it always executes via an absolute path.

Note: Codex integrates through the official hooks system in ~/.codex/hooks.json and currently subscribes only to PermissionRequest and Stop. After first install, run /hooks inside Codex to complete the trust review.

Grok: Writes ~/.grok/hooks/agent-notify.json. Global hooks are always trusted; project hooks (.grok/hooks/) require /hooks-trust or --trust. After install, run /hooks (or Ctrl+L) inside Grok to confirm they loaded.

You don't need to edit config files by hand — this section is for reference only.

Agent Notify's own config lives at ~/.agent-notify/config.yaml. New installs start with all agents and channels disabled — run npx agent-notify@latest (setup wizard) once to enable the agents and channels you want. This avoids showing unconfigured agents as ready in view/doctor after a partial setup. Existing config files are left unchanged.

Agent integration config locations:

  • Claude Code: ~/.claude/settings.json (writes hooks → command agent-notify handle-claude-hook)
  • Codex: ~/.codex/hooks.json (writes hooks → command agent-notify handle-codex-hook; run /hooks inside Codex to complete trust)
  • OpenCode: ~/.config/opencode/opencode.json (writes plugin array → ~/.agent-notify/opencode-plugin.js, command agent-notify handle-opencode-hook; project scope uses ./opencode.json)
  • ZCode: ~/.zcode/cli/config.json (writes hooks.events.<Event> + hooks.enabled → command agent-notify handle-zcode-hook; restart ZCode for the config to take effect)
  • Grok: ~/.grok/hooks/agent-notify.json (writes hooks → command agent-notify handle-grok-hook; project scope uses .grok/hooks/agent-notify.json)
  • Droid: ~/.factory/hooks.json (writes hooks → command agent-notify handle-droid-hook; project scope uses .factory/hooks.json)
  • OMP: ~/.omp/agent/extensions/agent-notify.ts (writes a native TypeScript extension; project scope uses .omp/extensions/agent-notify.ts)
  • DeepSeek Harness: <DSH_HOME>/profiles/<profile>/package.json (registers the agent-notify-dsh bundle; the install itself runs dsh plugin --profile <profile> add agent-notify-dsh. DSH has no project-level install location)

WeChat Work Bot Binding Tip

  1. Create a single-person notification group: start a group chat in WeChat Work (pull in a few colleagues). After it's created, do not post anything, then remove the others — the group becomes your personal notification channel.
  2. Add a bot: "Group Settings" → "Message Push" → "Add" → "Custom Message Push", name it and save.
  3. Get the webhook URL: copy the generated URL, which looks like https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx.
  4. Bind it: run npx agent-notify@latest, enable the WeChat Work channel in the setup wizard, and paste the webhook URL.

Older WeChat Work versions: "Group Settings" → "Group Bots" → "Add Bot" → "New Bot", name it and save.

Workflow diagram

Screenshots

Setup Feishu binding
Setup Feishu Binding
Feishu notification WeChat Work notification
Feishu Notification WeChat Work Notification
System notification
System Notification

Acknowledgments

Thanks for the support and feedback from the friends at LINUX DO.