Notifications

Native macOS banners — they respect Focus and Do Not Disturb like anything else. There are two kinds, both configured in Settings… → Notifications.

Session alerts

Fire when a session wants you — for every session running on your Mac: CLI, IDE extensions, and local sessions in the Claude and ChatGPT desktop apps. Remote sessions are stored off your machine, so there is nothing local to watch. Two independent toggles:

  • Waiting for your input — a session is blocked on a question or a plan review.
  • Task finished — a session ended a turn and handed control back.

Both fire on every matching event while enabled. There is no “only if it took longer than N minutes” gate; the only suppression is a short per-session rate limit so a chatty session can’t spam you. Banners group per session in Notification Center.

The banner subtext is the project folder name — the last component of the session’s working directory. The title already carries the message, so the hook’s own text isn’t repeated.

Click a banner to focus the session

  • IDE sessions — the workspace window (VS Code, Cursor, Windsurf, JetBrains), opened through LaunchServices so no security prompt appears.
  • CLI sessions — the terminal app, detected generically as the GUI app that owns the session. Works with Terminal, iTerm2, Warp, Ghostty, WezTerm and anything else; there is no hardcoded list.
  • Codex sessions in the ChatGPT desktop app — the app itself, activated without a folder since it has no window bound to one.

A session that can’t be resolved is a silent no-op rather than an error.

Usage alerts

Fire when session-window or weekly utilization crosses a threshold — 80% by default, and the list is editable. Each threshold fires once per crossing: it stays silent while you remain above the line and re-arms only when utilization drops back below it. The armed state survives relaunches, and this polling runs even when the menu bar percentage is hidden.

How session alerts actually work

Two entry points, deliberately non-overlapping, so each event fires exactly once.

Terminal (cli) sessions use a Claude Code hook. BlackFlare installs Notification and Stop hooks in ~/.claude/settings.json pointing at a small bundled blackflare-hook forwarder. Claude Code runs it at ask-time and turn-end, so the banner fires the instant Claude blocks — even when the transcript write is still buffered on disk, which is exactly the case a transcript-only watch misses for terminals.

IDE sessions use the transcript watch. BlackFlare watches ~/.claude/projects/*/*.jsonl with kernel-level FSEvents, reads only the newly appended bytes, and distinguishes an unanswered AskUserQuestion or ExitPlanMode (waiting) from a turn-ending end_turn that ran long enough (task done). Every transcript is seeked to end-of-file at launch, so starting BlackFlare never replays your history as a burst of banners.

The FSEvents path emits nothing for cli sessions — that is the hook’s job — so a terminal session can never produce a duplicate banner.

“Task finished” is rate limited to at most one per session per 30 seconds on both paths. Everything stays on your machine: the hook relay carries only the event, message, session ID and working directory; the transcript watch reads locally. No content leaves your Mac.

When a session spawns background subagents, its “Task finished” banner is held until the main session itself settles after those subagents report back — not the moment a subagent exits, which is still mid-work. Subagents never post a banner of their own, so one finish means one banner rather than one per subagent.

One deliberate simplification: permission-pending is not its own banner. Every Notification event reads as “waiting”.

Codex notifications

Codex needs no hook. BlackFlare tails ~/.codex/sessions/**/rollout-*.jsonl and fires “Codex finished a task” on each task_complete — covering CLI, VS Code, and ChatGPT desktop app sessions, since they all write to the same rollout tree.

When Codex pauses mid-task to ask you a question, BlackFlare fires a distinct “Codex is waiting for you” notification — desktop and Telegram/Slack — instead of staying silent until the task finishes. It mirrors the Claude waiting banners and honors the same “Waiting for your input” toggle.

Approval prompts are the exception: they never reach the rollout file, so a session paused on an approval shows no waiting banner — only questions do. Nothing is ever guessed into “waiting”. Because Codex reports the same source for the VS Code extension and the desktop app, BlackFlare tells the host apart by the rollout’s originator.

Delivery is gated by the Codex provider toggle plus the shared “Waiting for your input” and “Task finished” toggles — symmetric with Claude, with no separate Codex alert switch.

What BlackFlare writes to settings.json

Only its own Notification and Stop entries, identified by the blackflare-hook command. Your other hooks and every other byte are untouched, and an install → uninstall round-trip is byte-identical. Turning a session toggle off removes the matching hook. Moving the app repairs the stale helper path on the next launch. Changes apply to your next Claude Code session.