anotifier / docs
[ REFERENCE · v1.7.1 ]

anotifier documentation.

Everything the package does, in one page: install, the setup wizard, every command, every config key, the agents and events it hooks, the channels it delivers to, and what happens when something fails.

$ npx anotifier@latest setup

Updated 2026-10-16 for v1.7.1 · plain-text version for LLMs · README on GitHub

What is anotifier?

anotifier is a free, open-source, zero-dependency Node.js CLI that sends a notification when an AI coding agent finishes a task or needs your input.

It hooks into the native event system of Claude Code, OpenAI Codex CLI, Cursor, Google Gemini CLI, and Antigravity CLI, then delivers to the channels you enable: a desktop toast (Windows, macOS, Linux, WSL), a phone push via ntfy (Android and iOS, no account), a webhook (Slack, Discord, Telegram, or any HTTP endpoint), and a terminal bell. All agents share one config file at ~/.anotifier/config.json.

  • License: AGPL-3.0. Source on GitHub, package on npm.
  • Runtime: Node.js 18 or newer, which every supported agent already requires.
  • Dependencies: none. Pure Node.js built-ins; npm i -g anotifier installs exactly one package.
  • Privacy: everything runs locally. Only the notification text goes to the channels you configure, and phone push is generic by default. The one exception: version 1.3.0 and later can send opt-in anonymous usage stats if you say yes during an interactive anotifier setup or run anotifier telemetry on; they are off otherwise (see the usage stats section below).

How do I install anotifier?

Run one command; the setup wizard detects your platform and installed agents and wires the hooks.

npx anotifier@latest setup

Restart your AI tools afterwards so they pick up the new hooks. Other install paths:

# Global install, then run the wizard
npm i -g anotifier
anotifier setup

As a Claude Code plugin (hooks auto-register; run /anotifier:setup inside Claude Code to wire the other agents):

/plugin marketplace add DevinoSolutions/anotifier-for-claude-codex-cursor
/plugin install anotifier@anotifier

Standalone, without npm:

# Windows (PowerShell)
irm https://raw.githubusercontent.com/DevinoSolutions/anotifier-for-claude-codex-cursor/main/setup/install.ps1 | iex
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/DevinoSolutions/anotifier-for-claude-codex-cursor/main/setup/install.sh | bash
PlatformRequirementNotes
AllNode.js ≥ 18Already present for every supported agent.
WindowsPowerShell 7+ (pwsh)Toasts use the BurntToast module; setup installs it if missing. See Claude Code and Codex notifications on Windows.
macOSosascriptBuilt in. No extra install.
Linuxnotify-send (libnotify)Optional, for desktop toasts. Without a desktop session the toast fails, is logged to ~/.anotifier/errors.log, and the other channels still deliver.
WSLWSL2 interop + Windows PowerShellBoth on by default. Toasts are routed to Windows; see how the toast crosses from WSL into Windows.

What does the setup wizard change on my machine?

It writes one shared config, then adds hook entries to each detected agent's own config file, backing up every file it touches first.

  1. Detects the platform and which agents are installed (looks for ~/.claude/settings.json, ~/.codex, ~/.cursor, ~/.gemini).
  2. Prepares the toast backend: installs BurntToast on Windows, confirms osascript on macOS or notify-send on Linux.
  3. Asks whether to enable phone push via ntfy and generates a random topic like anotifier-<16 random chars>.
  4. Saves ~/.anotifier/config.json.
  5. Patches each agent's hook config (table below) and copies the original to ~/.anotifier/backups/ first.
  6. Prints the ntfy topic URL to subscribe to in the ntfy app.
AgentFile patchedHook events registered
Claude Code~/.claude/settings.jsonStop, Notification
Codex CLI~/.codex/hooks.json (+ hooks = true under [features] in ~/.codex/config.toml)Stop, PermissionRequest, SessionStart
Cursor~/.cursor/hooks.jsonstop
Gemini CLI~/.gemini/settings.jsonAfterAgent, Notification

Each hook runs node <path>/src/notify.mjs --source <agent> with the agent's event JSON on stdin. The agent gives the hook 10 seconds (Claude Code, Codex) or 30 (Gemini CLI); inside that, every channel runs in parallel with its own shorter timeout (5 to 7 seconds), and the hook always exits successfully, so a broken channel can never stall the agent.

Which CLI commands does anotifier have?

Seven commands: setup, status, test, config, doctor, snooze, and uninstall.

anotifier setup            # First-time setup wizard
anotifier status           # Wired tools, config summary, recent hook errors
anotifier test [channel]   # Fire a test notification (toast | ntfy | webhook | bell | both)
anotifier config [section] # Interactive settings (ntfy | webhook | sounds | events | sentry)
anotifier doctor [--deep]  # Diagnose delivery per channel (--deep verifies real delivery)
anotifier snooze [dur]     # Silence every channel (30m | 2h | 90s | 45 = 45 minutes)
anotifier snooze off       # Cancel the snooze early
anotifier uninstall        # Remove anotifier's hooks from every agent
anotifier --version        # Version, plus an update notice if one is available
CommandWhat it doesExit code
setupDetects agents, writes config, patches hooks, backs up originals.1 if no agent was found or any patch failed.
statusShows version, platform, toast backend, Sentry, snooze, quiet hours, usage alerts, context alerts (1.6.0 and later) and whether the Claude Code statusline is wired (1.5.0 and later), ntfy URL, webhook origin, wired tools with their events, per-event toggles, and the last 8 hook errors from ~/.anotifier/errors.log.1 if the config file is invalid.
test [channel]Sends a real test notification through one channel or all enabled ones.1 for an unknown channel name.
config [section]Interactive editor for ntfy, webhook, sounds, events, or sentry. Writes once at the end; Ctrl+C saves nothing.1 when not run in a terminal.
doctor [--deep] [--json] [--strict]Static checks for config, toast backend, bell, ntfy, and webhook. --deep fires a marker notification and reads it back from Notification Center (macOS) or dunst history (Linux). --json prints machine-readable output. --strict turns deep warnings into failures.1 if any check fails.
snooze [dur|off]Silences all channels until the deadline stored in ~/.anotifier/.snooze.json. No argument prints the current state.1 for an unparseable duration.
uninstallRemoves only the hooks anotifier manages, and puts your original Claude Code statusline back (1.5.0 and later). Your own hooks and the backups stay.0

Which agent events trigger a notification?

Three normalized events: task_complete, needs_input, and session_start.

EventMeaningDefault toast soundDefault priorityDefault ntfy tags
task_completeThe agent finished its turn.IMdefaultwhite_check_mark
needs_inputThe agent asked a question or wants permission to run a tool.Reminderurgentbell,warning
session_startA new session started (Codex only). Every channel is off for this event by default, the webhook included from 1.7.1 (before 1.7.1 an enabled webhook still received it). Set webhookEnabled: true (or toastEnabled, ntfyEnabled, terminalBellEnabled) to get it on that channel.Defaultlowrocket
Agenttask_complete comes fromneeds_input comes from
Claude CodeStop hookNotification hook (permission prompts, questions)
Codex CLIStop hookPermissionRequest hook (approval to run a command)
Cursorstop hook—
Gemini CLIAfterAgent hookNotification hook

Every notification is titled <project> · <agent> (for example my-app · Claude Code), where the project is the name of the working directory the agent runs in. The body is <project>: Task complete or <project>: Needs your input, unless rich content replaces it (see below).

Duplicate hook fires within 1.5 seconds for the same agent, event, and session are collapsed by an atomic lock file, so Cursor's double stop produces one notification.

Which notification channels are supported?

Desktop toast, phone push via ntfy, webhook, and terminal bell. Each is toggled independently and can be disabled per event.

Desktop toast

OSBackendDetails
WindowsBurntToast (PowerShell 7+)Per-agent icon, per-event sound (Default, IM, Mail, Reminder, SMS, Alarm), click-to-focus via a custom agentfocus:// URI that brings the terminal or VS Code window that fired the hook to the front.
macOSosascriptBuilt in. Windows sound names are mapped to the closest system sound; unknown names fall back to the default sound.
Linuxnotify-send (libnotify)Event priority maps to notify-send urgency. Sound names are ignored.
WSLPowerShell interopDetected automatically; toasts cross to the Windows host instead of needing a Linux notification daemon.
{
  "toast": {
    "enabled": true,
    "clickToFocus": true,
    "richContent": true
  }
}

Phone push (ntfy)

ntfy is a free, open-source pub/sub push service with Android and iOS apps and no account requirement. anotifier publishes to one topic; every device subscribed to it gets every agent's alerts in one stream.

  1. Install the ntfy app: Android (io.heckel.ntfy on Google Play) or iOS (App Store).
  2. Run anotifier setup and answer yes to phone notifications, or add the block below.
  3. Subscribe in the app to the topic shown during setup, for example https://ntfy.sh/anotifier-k3j9x2m1p8q4r7s6.
  4. Run anotifier test ntfy. Your phone should buzz within a second.
{
  "ntfy": {
    "enabled": true,
    "server": "https://ntfy.sh",
    "topic": "anotifier-<random>",
    "click": "",
    "richContent": false
  }
}
  • server: any ntfy server, including a self-hosted one.
  • fallbackServer (1.7.0 and later, optional): a second ntfy server. If server fails (unreachable, a timeout, or an error answer such as a 429 daily limit), the same push is sent once to the fallback with the same topic. With a fallback set, each attempt waits at most 3 s instead of 5 s. For example, set your own server as server and https://ntfy.sh as fallbackServer, and subscribe your phone to the topic on both. If the main server accepts a push but answers slowly, a phone subscribed on both can get it twice. anotifier status shows a fallback line, and anotifier test ntfy warns when only the fallback delivered.
  • click: URL opened when you tap the notification. Empty means no link.
  • richContent: off by default for privacy. Public ntfy.sh topics are guessable, so the body stays generic (my-app: Task complete) unless you run a private server and opt in.
  • Event priority (min, low, default, high, urgent) becomes the ntfy push priority; ntfyTags become the emoji tags.
  • Non-ASCII titles (the · separator, non-Latin project names) are RFC 2047-encoded in the HTTP header and decoded by ntfy, so they display correctly.

Webhook (Slack, Discord, Telegram, generic)

Set webhook.enabled to true and a webhook.url. format picks the payload shape. authorization, if set, is sent as the Authorization header for every format.

{
  "webhook": {
    "enabled": true,
    "url": "https://hooks.slack.com/services/...",
    "format": "slack",
    "richContent": true
  }
}
formatURL to usePayload
slackSlack Incoming Webhook URLSlack message JSON.
discordDiscord channel webhook URL{ content } with the title in bold and the message on the next line. See the Discord page.
telegramhttps://api.telegram.org/bot<token>/sendMessage plus chatId{ chat_id, text } with the title and message on two lines.
genericAny HTTPS endpoint{ title, message, source, project, event, timestamp } as JSON.

Terminal bell

An audible ding in the terminal that launched the agent. For Claude Code 2.1.141 and newer it rings through Claude Code's own terminal write path (the terminalSequence field in the hook reply), which is safe in tmux, GNU screen, and on Windows. Other agents get a direct BEL byte to the controlling terminal. anotifier doctor warns when your terminal is known to swallow the bell.

{ "terminalBell": { "enabled": true } }

What does the notification actually say?

For Claude Code, toasts and webhooks show what the agent said or asked, read from the session transcript; other agents and phone push get the generic text.

A needs_input notification carries Claude's own question; a task_complete notification carries the last assistant message. Both are collapsed to one line and trimmed to about 180 characters. Session-start notifications stay generic. anotifier reads the transcript for Claude Code only, so Codex, Cursor, and Gemini CLI always get <project>: Task complete style text. The project name stays in the title on every channel, so a rich body never hides which repo finished. Cursor is the exception: anotifier doesn't read a project folder from its stop event, so Cursor alerts are titled just Cursor.

ChannelConfig keyDefaultWhy
Toasttoast.richContenttrueYour own screen.
Webhookwebhook.richContenttrueYour own endpoint.
ntfyntfy.richContentfalsePublic ntfy.sh topics are guessable; conversation text must not leak there.

What are all the config options?

One JSON file, ~/.anotifier/config.json, shared by every agent. Missing keys fall back to these defaults.

{
  "ntfy": { "enabled": true, "server": "https://ntfy.sh", "topic": "", "click": "", "richContent": false },
  "toast": { "enabled": true, "clickToFocus": true, "richContent": true },
  "terminalBell": { "enabled": true },
  "webhook": { "enabled": false, "url": "", "format": "generic", "richContent": true },
  "sentry": { "enabled": false, "dsn": "" },
  "updateCheck": { "enabled": true },
  "usageAlerts": { "enabled": true, "thresholds": [70, 85, 95] },
  "contextAlerts": { "enabled": true, "threshold": 85 },
  "quietHours": { "enabled": false, "from": "22:00", "to": "08:00" },
  "events": {
    "task_complete": { "toastSound": "IM", "priority": "default", "ntfyTags": "white_check_mark" },
    "needs_input": { "toastSound": "Reminder", "priority": "urgent", "ntfyTags": "bell,warning" },
    "session_start": {
      "toastSound": "Default", "priority": "low", "ntfyTags": "rocket",
      "toastEnabled": false, "ntfyEnabled": false, "terminalBellEnabled": false, "webhookEnabled": false
    }
  },
  "sources": {
    "claude": { "label": "Claude Code", "icon": "https://…/claude-app-icon.png" },
    "codex": { "label": "Codex", "icon": "https://openai.com/favicon.ico" },
    "gemini": { "label": "Gemini", "icon": "https://…/gemini_sparkle.svg" },
    "cursor": { "label": "Cursor", "icon": "https://cursor.com/apple-touch-icon.png" }
  }
}
KeyTypeDefaultDescription
ntfy.enabledbooleantrueSend phone push notifications.
ntfy.serverURLhttps://ntfy.shntfy server, public or self-hosted.
ntfy.fallbackServerURLunsetOptional second ntfy server, tried once if ntfy.server fails (1.7.0 and later).
ntfy.topicstring""Topic to publish to. Set by the wizard.
ntfy.clickURL""Opened when you tap the push. Empty = none.
ntfy.richContentbooleanfalsePut the agent's words in the push body. Keep off on public servers.
toast.enabledbooleantrueDesktop toasts.
toast.clickToFocusbooleantrueClicking the toast focuses the originating window (Windows); how it picks the window.
toast.richContentbooleantrueClaude Code toasts show the transcript snippet.
terminalBell.enabledbooleantrueRing the launching terminal.
webhook.enabledbooleanfalsePOST to a webhook.
webhook.urlURL""Destination. Treated as a secret.
webhook.formatenumgenericgeneric, slack, discord, or telegram.
webhook.chatIdstring—Telegram chat id (telegram format only).
webhook.authorizationstring—Sent verbatim as the Authorization header.
webhook.richContentbooleantrueClaude Code webhooks carry the transcript snippet.
sentry.enabledbooleanfalseMirror hook errors to your own Sentry project. Opt-in, zero-dependency envelope client, error data only.
sentry.dsnstring""Your Sentry DSN.
updateCheck.enabledbooleantrueAsk the npm registry at most once a day and announce a new version at most once per version through your existing channels (never the bell). false disables the check and its state file entirely.
usageAlerts.enabledbooleantrueClaude Code only, 1.5.0 and later. Warn before a usage limit; false turns the warnings off (the statusline keeps working).
usageAlerts.thresholdsnumber[][70, 85, 95]Percentages above 0 and at most 100 at which the 5-hour and weekly windows each warn once. An invalid list is reported and the default applies.
contextAlerts.enabledbooleantrueClaude Code only, 1.6.0 and later. Warn once per chat before it auto-compacts; false turns the warning off (the statusline and the usage warnings keep working).
contextAlerts.thresholdnumber85Percentage above 0 and at most 100 of the auto-compact window at which a chat warns once. An invalid value is reported and 85 applies.
quietHours.enabledbooleanfalseSilence all channels inside a daily window.
quietHours.from / toHH:MM22:00 / 08:00Local time, 24-hour. Start inclusive, end exclusive, may span midnight.
events.<event>.toastSoundstringper eventWindows BurntToast sound name; mapped on macOS, ignored on Linux.
events.<event>.priorityenumper eventmin, low, default, high, urgent. Drives ntfy priority and Linux urgency.
events.<event>.ntfyTagsstringper eventComma-separated ntfy emoji tags.
events.<event>.toastEnabledbooleantruePer-event toast switch.
events.<event>.ntfyEnabledbooleantruePer-event push switch.
events.<event>.webhookEnabledbooleantruePer-event webhook switch.
events.<event>.terminalBellEnabledbooleantruePer-event bell switch.
events.needs_input.idleReminderPriorityenumdefaultPriority for Claude's "waiting for your input" idle reminder only.
sources.<agent>.labelstringper agentName shown in the title.
sources.<agent>.iconURLper agentIcon URL used by toasts and ntfy.

How do I pause notifications?

Use snooze for a one-off pause and quiet hours for a recurring nightly window. Either one alone silences every channel.

anotifier snooze 30m     # also 2h, 90s, or a bare number of minutes (45)
anotifier snooze         # prints "Snoozed until 14:32" or "Not snoozed"
anotifier snooze off     # cancel early
{ "quietHours": { "enabled": true, "from": "22:00", "to": "08:00" } }
  • Snooze survives reboots: the deadline lives in ~/.anotifier/.snooze.json and expires on its own.
  • Quiet hours use your machine's local time. 22:00 to 08:00 covers 22:00–23:59 and 00:00–07:59. from equal to to turns the feature off rather than silencing a full day.
  • A silenced run sends nothing on any channel, including the update notice, but the hook still exits 0 and still returns the reply its agent expects, so silencing can never stall Claude Code, Codex, Cursor, or Gemini CLI.
  • anotifier status shows both the snooze deadline and whether you are inside the quiet window right now.

How do I get warned before a Claude Code usage limit?

Version 1.5.0 and later sends one notification when your Claude Code 5-hour or weekly usage crosses 70%, 85% and 95%, on Claude.ai Pro and Max plans.

  • The title names the window and the percentage (Claude Code · 5-hour limit at 72%); the body names the chat, the threshold and the reset time. Priority is default at 70%, high at 85% and urgent at 95%.
  • Usage belongs to your account, so each threshold warns once per window across all your chats. A jump past several thresholds sends only the highest.
  • Claude Code reports usage (rate_limits) only to Claude.ai Pro and Max subscribers, and only to its statusline command. anotifier setup therefore routes the Claude Code statusline through src/statusline.mjs. A statusline you already have is wrapped and still prints your line; with none, anotifier prints model · 5h N% · 7d N%. anotifier uninstall restores the original.
  • Warnings go to the toast, ntfy and webhook channels you have on, never the terminal bell. Snooze and quiet hours hold them back without recording them, so a threshold crossed in that time is announced after it ends.
  • Configure it with usageAlerts.enabled and usageAlerts.thresholds (see the config table). A plugin-only install does not run setup, so wire statusLine by hand to src/statusline.mjs.
{ "usageAlerts": { "enabled": true, "thresholds": [70, 85, 95] } }

How do I get warned before Claude Code auto-compacts a chat?

Version 1.6.0 and later sends one notification per Claude Code chat when its context passes 85% of the auto-compact window, so you can wrap up or run /compact first.

  • The title carries the percentage (Claude Code · context at 87%); the body names the chat and the size, such as 174K of 200K tokens. Priority is high.
  • Each chat (Claude Code session_id) warns once and never again, even after /compact brings its context back down. /clear starts a new session, which can warn again.
  • The window is the auto-compact window, not the model's full one: the CLAUDE_CODE_AUTO_COMPACT_WINDOW environment variable, then the autoCompactWindow setting that /autocompact writes (clamped to 100K to 1M), then the model's own window. It never exceeds the model's window.
  • Nothing is sent when auto-compact is off (DISABLE_AUTO_COMPACT or DISABLE_COMPACT set to a true value, or autoCompactEnabled: false). The --autocompact flag and managed settings are invisible to a statusline, so with either the warning can be late or missing.
  • No Claude.ai subscription is needed: API-key and proxy sessions get the warning too. It uses the same statusline wiring as the usage warnings, so anotifier setup covers both; a plugin-only install must wire statusLine by hand.
  • It goes to the toast, ntfy and webhook channels you have on, never the terminal bell. Snooze and quiet hours hold it back without recording it. Configure it with contextAlerts.enabled and contextAlerts.threshold (see the config table).
{ "contextAlerts": { "enabled": true, "threshold": 85 } }

What happens when a notification fails?

The agent is never interrupted. The error is appended to ~/.anotifier/errors.log and shown by anotifier status.

  • Hook processes always exit 0 and always return the JSON the agent expects, even after an internal error.
  • anotifier status lists the last 8 hook errors with timestamp and context, and points at the log file.
  • anotifier doctor runs static checks per channel; doctor --deep sends a real marker notification and reads it back from Notification Center (macOS) or dunst history (Linux). Windows gets a static PowerShell + BurntToast + execution-policy check; the Windows and WSL troubleshooting table maps each error to a fix.
  • Opt-in Sentry mirroring (sentry.enabled + sentry.dsn) sends error events only, through a built-in zero-dependency client. No SDK is bundled.

Does anotifier collect usage stats?

Only if you say yes, and only in version 1.3.0 and later (1.2.6 and earlier send nothing). They are off by default; a plugin-only install never runs setup, so it never sends any.

# 1.3.0 and later only
anotifier telemetry        # on/off, your install id, and the exact counts waiting to be sent
anotifier telemetry off    # stop, and delete the local install id and pending counts
anotifier telemetry on
  • Version 1.3.0 and later: the first anotifier setup you run in an interactive terminal asks (default Yes). A setup that is piped, run through an agent, or whose input closes never asks and leaves stats off, and re-running setup never overrides your earlier choice.
  • Version 1.3.0 and later: events go to the project's self-hosted PostHog at posthog.devino.ca, readable by the anotifier maintainers, keyed by a random install id in ~/.anotifier/.telemetry.json. The server is configured to discard client IP addresses and no location is derived.
  • Version 1.3.0 and later: anotifier telemetry shows your install id; anotifier telemetry off deletes it locally. To have data already sent removed, open a GitHub issue with the id.
  • Version 1.3.0 and later: CLI commands report the command, a clamped argument shape (known flags such as --deep or off, everything else as other), exit code and duration, plus setup (agents found, backend ready, config rebuilt) and the per-channel results of test, doctor and uninstall. Errors report only a clamped error class name and code.
  • Version 1.3.0 and later: hook runs are counted locally and sent as one summary a day: delivered or failed per agent, event and channel, why a notification was skipped, unrecognized hook event names (clamped to 40 safe characters, at most 10), a latency bucket, which features are on, and your OS, architecture and Node and anotifier versions.
  • Version 1.3.0 and later, never sent: message text, project names, file paths, ntfy topics or servers, webhook URLs, hostnames, session ids, or error messages. The README lists every event and property.
  • Version 1.3.0 and later: DO_NOT_TRACK=1, ANOTIFIER_TELEMETRY=0, or a CI environment turns it off regardless of the setting.

How do I uninstall anotifier?

Run anotifier uninstall. It removes only the hooks anotifier manages, restores your statusline (1.5.0 and later), and leaves your own hooks and its backups in place.

anotifier uninstall
# then, if you installed globally
npm uninstall -g anotifier

Codex trust hashes that anotifier added under [hooks.state] in ~/.codex/config.toml are removed too. Original configs remain at ~/.anotifier/backups/ for you to keep or delete, along with ~/.anotifier/config.json.

How is anotifier tested?

Against the real agents and real operating systems, with the delivered notification read back out of each OS's own notification store.

  • Unit and integration suites run on Linux, macOS, and Windows for every change.
  • End-to-end lanes install the real Claude, Codex, and Gemini CLIs from npm, drive them, and assert a real ntfy.sh push round-trips. The Cursor lane checks the config wiring only.
  • Toast lanes fire the real backend, then read the record back from dunst history plus an OCR of the on-screen banner (Linux), Notification Center's SQLite database (macOS), and wpndatabase.db (Windows). A silently dropped toast turns CI red.
  • A tmux lane drives the real Codex TUI through an approval modal and proves the PermissionRequest alert fires.
  • Every lane is required and hard-fails; live status badges are on the GitHub README.

Frequently asked questions

Does anotifier send my code or conversation anywhere?

No. It runs locally with zero dependencies. Only the notification text goes to channels you configured yourself, and phone push is generic by default because public ntfy topics are guessable. Version 1.3.0 and later can also send opt-in anonymous usage stats, which are off unless you say yes and never include code, conversation, message text, paths or topics.

Which AI coding agents does anotifier support?

Claude Code (terminal and VS Code extension), OpenAI Codex CLI, Cursor's agent, Google Gemini CLI, and, from 1.4.0, Google's Antigravity CLI. All are wired by one setup command and share one config. Antigravity CLI, which replaced Gemini CLI for Google AI Pro and Ultra subscribers, uses its own hook file (~/.gemini/config/hooks.json); anotifier wires its Stop event, so it alerts on "Task complete" and sends no needs-input alert (Antigravity hooks have no such event; Antigravity's own notifications setting covers permission prompts and questions). It has not yet been tested against a live Antigravity CLI.

Does it work inside VS Code?

Yes. The hooks fire whether the agent runs in a standalone terminal, the VS Code integrated terminal, or the Claude Code extension, and no VS Code extension is required. On Windows, clicking the toast brings forward the window whose title contains the project folder.

Can a broken notification break my agent?

No. Hooks always exit successfully and return the reply the agent expects. Failures go to ~/.anotifier/errors.log and appear in anotifier status.

Do I need an account for phone notifications?

No. ntfy is free and account-free. Install the app, subscribe to the topic setup prints, done. You can point anotifier at a self-hosted ntfy server too.

Can I approve Codex or Claude permission prompts from my phone?

Not yet. anotifier alerts you the instant an approval is requested and, on Windows, click-to-focus brings you back to the right window, but the decision is made at the keyboard. Remote Allow/Deny is on the roadmap pending a security design.

How do I stop getting a notification for one event?

Set the per-event switch, for example events.session_start.toastEnabled: false, or events.task_complete.webhookEnabled: false. Use snooze or quiet hours to silence everything for a while.

Is anotifier free?

Yes. It is open source under AGPL-3.0 with no paid tier and no account. Version 1.3.0 and later offer opt-in usage stats that never include message text, paths or topics. Sponsorship is welcome but never required.

Where next?

Per-agent setup guides, a comparison with the alternatives, and the source.