Several AI agents working in parallel?
How do you know which finished and when?
Twira can let you know by a visible toast, a chime, or a verbal notification saying which agent just finished. You’re working with several agents, or moving between tasks. You don’t want to be switching between terminals constantly checking. Notifications lets you know when, and which agent has finished and is ready for you to review.
Get notified which agent is finished. No guessing.
/agent-name "<label>"Names this session for every notification surface in one slash command.
twira notify testFire a test toast, verifies the visible + audible path works.
twira notify speak-testExercise the TTS path end-to-end; reports which provider fired.
twira notify set-keyStore an Azure Speech key (stdin only, never in shell history).
/ar-dash → /notificationsEdit preferences: allowlist, severity floor, voice overrides.
You ask
“Three coding sessions in parallel. Each on a different task. You step away for coffee.”
Twira instantly
- Session 1, Claude Code: /agent-name "Auth bug"
- Session 2, Gemini CLI: /agent-name "Refactor"
- Session 3, Codex CLI: /agent-name "Deploy"
- Each agent’s lifecycle hook fires Ready / Question / Permission as appropriate
- Toasts appear with full names; per-event chimes play; per-agent voices speak
You hear which agent finished, and which one is asking a question. You stay in flow on the next task.
How you use this
Just type: /agent-name Dashboard Designer And this agent gets called Dashboard Designer The terminal gets rename Dashboard Designer The Notifications tell you its Dashboard Designer AND the other Agents get to know that Dashboard Designer is working alongside them
When you reach for it
- Naming a coding session so notifications, terminal tab, voice readout, and audit-chain actor all carry your label. /agent-name "Auth bug" is the one-line setup that makes every other surface here useful.
- Long-running work, big refactors, multi-step ports, full test suites, where you want to context-switch and have the agent ping you when it needs you back, with a voice that tells you which agent needs you so you do not have to look.
- Running two or three parallel sessions, each named differently, and listening for the right voice and name to know which one finished. "Claude Auth bug has finished" vs "Gemini Refactor has a question", different agent, different voice, different session, all clearly distinguishable.
- Walking away from the desk while the agent works. Local TTS works offline with no extra setup; upgrade to Azure Speech neural voices if you want it to sound less robotic.
- Multi-monitor setups where the agent chat is on a side screen. The toast banner, audible chime, and voice readout mean you do not have to keep looking over.
- Building internal alerting on top of Twira’s event bus. Broaden the kind allowlist to ["*"], drop the severity floor, and treat the OS-level toast and voice as the alert path.
See it work
$ # 1. After twira init, confirm the visible and audible path works:
recon notify test
# 2. Try the spoken voice readout (uses local TTS by default):
recon notify speak-test
# 3. Name your session, every notification from now on includes the name:
/agent-name "Auth bug investigation"
# 4. Optional, upgrade to Azure neural voices (key piped from stdin):
echo "<azure-speech-key>" | twira notify set-key
recon notify key-status
# 5. Edit preferences in the dashboard (allowlist, severity, voice override):
/ar-dash → /notificationsWithout /agent-name, every toast just says "Claude has finished."
Multi-session disambiguation depends on /agent-name. The toast title, terminal tab, audit-chain actor, and spoken phrase all use the label you set. Without it, three parallel Claude sessions all fire identical "Claude has finished" toasts, and macOS coalesces them into one. One slash command per session at the start is the cost; everything else here pays back from it.
Technical depth, for engineers who want it
In your editor
Your editor’s terminal beeps when a build fails. Your IDE pings when a test breaks. Notifications do the same for your AI agent, Ready, Question, Permission. Toast, chime, voice. And because you might be running three sessions in parallel, the toast title and the spoken phrase both name the agent and the session, so you know which one finished without looking up.
What Notifications does
Notifications hooks every coding agent’s lifecycle (Ready, Question, Permission) into your operating system. Native OS toast banners, WinRT on Windows, osascript on macOS, D-Bus on Linux. A per-event chime: glass on Ready, warning on Question, error on Permission. A spoken voice readout through local TTS (free, offline), Azure Speech (paid, neural), or OpenAI Audio (uses your existing key), with graceful fallback to local TTS if cloud fails. Per-agent voice mapping, Claude as Ryan, Gemini as Sara, Codex as Jenny by default, overridable globally or per agent. /agent-name "<label>" names the session for the toast title, terminal tab, audit-chain actor, and spoken phrase in one slash command. Activity toasts via the dashboard event bus cover webhook deliveries, rule matches, and audit writes. Per-event preferences in the dashboard reload fresh on every event, no restart.
How it actually works
You are in flow. The agent is doing work. You context-switch to Slack, to a PR review, to a coffee. The agent hits an error, asks for permission, finishes the build, and the answer is sitting unseen in the agent chat while you wait for nothing. Twira’s notification surface fixes that with three layers, in this order: a visible OS toast banner, an audible per-event chime, and an optional spoken voice readout that tells you which agent in which session needs you, by name, in a per-agent voice. Pair it with /agent-name and the system reads back exactly what you typed.
There are three lifecycle toast types. Ready means the agent has finished its turn and is waiting for your next input, toast title "Claude Auth bug has finished", glass chime. Question means the agent has a mid-task question, toast title "Claude Auth bug has a question", warning chime. Permission means the agent needs your sign-off to continue (run a Bash command, edit a file, call an MCP tool), toast title "Claude Auth bug needs permission", dialog-error chime. The title formula is {Agent} {SessionName} {suffix}, the agent identifier (Claude, Gemini, Codex) is detected automatically from the hook source, and the session name comes from /agent-name. Without a session name it degrades to "Claude has finished", which tells you it was Claude but not which Claude session. That is exactly the disambiguation /agent-name solves.
The toast is a native OS notification banner, same rendering as Slack pinging you or your calendar reminding you of a meeting. On macOS it appears top-right with the Twira app icon, the action title ("Claude Auth bug has finished"), a subtitle line carrying the session name ("Auth bug investigation"), and a contextual hint ("Ready for input"); the glass chime plays once and the toast auto-dismisses after about five seconds. On Windows 11 it appears bottom-right and lands in Action Center until dismissed. On Linux GNOME or KDE the same content is rendered via org.freedesktop.Notifications, title, body, subtitle, app icon. The subtitle on macOS is what defeats same-title coalescing (more on this below). The "Twira" app name and icon are registered via the AUMID on Windows so toasts attribute correctly rather than appearing under PowerShell.
Each lifecycle type carries a different platform sound, so you can distinguish "the build is done" from "the agent needs me to approve something" without looking at the screen. Sound names use the freedesktop standard (message-new-instant, dialog-warning, dialog-error); notify-rust maps them to platform equivalents on Windows and macOS automatically. You can silence sounds globally via the notifications.toastSound flag in Twira.json while keeping the visible toast, useful in a quiet office or shared room.
The voice readout is the layer that earns its keep on multi-session days. Twira can speak the notification out loud, in a per-agent voice, so you know which agent has finished without looking. The spoken phrase format is {Agent} {SessionName} has finished (or "needs your input" for Question and Permission). Type /agent-name "Auth bug" in Claude Code and the next notification says "Claude Auth bug has finished" in Ryan’s British accent (en-GB-RyanNeural). Type /agent-name "Refactor" in Gemini CLI and that session says "Gemini Refactor has finished" in Sara’s American accent (en-US-SaraNeural). Type /agent-name "Deploy" in Codex CLI and you hear "Codex Deploy has finished" in Jenny’s American accent (en-US-JennyNeural). Different voice per agent means you can tell who is asking without looking at the screen. Run two or three coding sessions in parallel and you can stay in flow on a fourth task, listening for the right voice.
Voice readout is provider-agnostic, with three providers and a graceful fallback chain. The default is local TTS, no key, no setup, no cost. macOS uses say (Daniel for British, Samantha for American, Karen for Australian, Moira for Irish, Rishi for Indian, plus French, German, Italian, Spanish, Japanese mapping). Windows uses SAPI via PowerShell, which has been part of Windows since XP. Linux uses espeak-ng, with espeak or spd-say as fallback. Works offline. Azure Speech is the paid upgrade, Azure pay-as-you-go, neural voices that sound dramatically better than offline TTS, authenticated via API key or Microsoft Entra ID bearer token. Set it up via the dashboard or via twira notify set-key (key is read from stdin so it never appears in shell history). OpenAI Audio is the third option, reusing your existing OPENAI_API_KEY (the same key as semantic search embeddings) with six voices: alloy, echo, fable, onyx, nova, shimmer. If a cloud provider fails (network error, missing key, auth failure), the speech path silently falls back to local platform TTS, so the agent is never silently muted. Cloud synthesis results are cached as WAV files at .Twira/.tts-cache/ keyed by text plus voice hash, with a 30-day eviction window, so the second time a phrase plays there is no network round-trip. Repeated phrases like "Claude has finished" are effectively free even on a paid provider.
The default voice map (Claude British male, Gemini American female, Codex American female) is a starting point. Override it globally in Twira.json under notifications.speech.voice = "en-US-GuyNeural", or per-agent under notifications.speech.voices with entries like { "claude": "en-AU-WilliamNeural", "gemini": "en-GB-LibbyNeural" }. All Azure neural voice names work. Per-agent overrides win over global; global wins over the default map.
Separately from the agent’s lifecycle hooks, the dashboard subscribes to Twira’s internal event bus and can fire OS notifications for any meaningful activity, rule matched, MCP disconnected, tool finished, audit chain entry written, PII redaction fired, webhook delivered, masterplan task claimed by another agent, and more. Default preferences are conservative: only RuleMatched events at Warning or above ping the OS. The allowlist supports ["*"] for every event kind, and the severity floor can drop to Info if you want fuller telemetry.
Preferences are edited in the dashboard at /notifications (one /ar-dash away). Toggle the master enable, set the severity floor (Info, Warning, Error, Critical), edit the kind allowlist as a free-text list, turn sound on or off, paste an Azure Speech key, set a voice override per agent. Preferences live in ~/.Twira/notification_preferences.json and are read fresh on every event, changes take effect within milliseconds, no restart. The same page exposes the browser’s Notification.requestPermission() flow so in-tab notifications work alongside desktop ones, and shows the current OS-permission status.
Cross-platform delivery is solved per-OS. Windows uses tauri-winrt-notification for proper WinRT toasts (twira init registers the AUMID, Application User Model ID, so toasts attribute to Twira rather than PowerShell). macOS uses osascript display notification rather than NSUserNotificationCenter because unsigned CLI binaries get silently dropped by the native centre; osascript routes through Script Editor.app, which is always permitted (this was a real macOS-only issue we solved). Linux uses D-Bus org.freedesktop.Notifications via notify-rust. Delivery failures never propagate, a missing notification is annoying, not a service failure.
macOS silently coalesces notifications with identical titles from the same app, which would mean three parallel Claude Code sessions all firing "Claude has finished" toasts get merged into one. Twira uses the session name as the notification subtitle, which macOS treats as a coalescing-distinguisher, so three sessions named differently produce three visible toasts. Another reason /agent-name earns its keep on multi-session days.
Every notification surface uses the agent name you set, toast title, terminal tab, voice readout, audit-chain actor. Without a name, every ping just says "Claude has finished" and you have no way to tell which Claude session in which task is asking. With a name, you get "Claude Auth bug has finished", instant, unambiguous identification across every parallel session you have running. To set it, type /agent-name "<label>" inside your coding agent, for example /agent-name "Auth bug investigation". The agent runs twira agent-name "..." under the hood, emits a SESSION_MARKER line so the hooks can read the name, and calls /rename to update the terminal tab in one go. From any terminal you can run twira agent-name "<label>" directly, useful for scripts, automation, or non-Claude harnesses.
The name shows up in five places. It is the macOS subtitle on every desktop notification (defeating the coalescing problem). It is the terminal tab title (Claude Code reads the slash command and calls /rename automatically). It is the audit-chain actor field, so when a reviewer asks "which agent committed this change?", the answer is "Claude Auth bug investigation" rather than "session 7a3f". It is the label on the dashboard’s sessions page and in the notifications history. And it is the spoken phrase in the voice readout. The command is called agent-name and not session-name because from your perspective at the keyboard you are working with an agent, Claude, Gemini, Codex, and naming it "Auth bug" is naming that agent for this run. The toast still concatenates the agent type with your label, so it reads "Claude Auth bug has finished" rather than just "Auth bug has finished", but the surface you interact with is the agent in front of you. The command name matches the mental model. Rename later by running it again; the audit chain records every rename so the timeline stays honest. Installed by twira init to both .claude/commands/agent-name.md (project) and ~/.claude/commands/agent-name.md (your home directory), the global copy means the slash command works even in projects that have not run twira init yet.
The twira notify <action> CLI gives you five operations. twira notify test fires a test toast, checks AUMID and permission setup, and reports whether speech is configured, run it after twira init to confirm notifications work on this machine. twira notify speak-test exercises the TTS path end-to-end; it tries cloud, falls back to local, and reports which provider fired. twira notify set-key stores an Azure Speech subscription key from stdin (interactive prompt with hidden echo, or piped), so the key never appears in shell history or process listings. twira notify clear-key removes the stored key. twira notify key-status reports whether a key is configured (env var or keyring) without ever printing the key itself.
Tier is Pro. Notifications is gated alongside the rest of the operator surface, the lifecycle hooks, dashboard event-bus toasts, per-event preferences, local TTS voice readout, per-agent voice mapping, terminal tab title sync, browser in-tab notifications. Azure Speech and OpenAI TTS remain optional upgrades you pay for to the cloud provider, not to Twira, your money, your voice-quality decision.
Setup is automatic. twira init installs the lifecycle hooks (wired into Claude Code, Gemini CLI, and Codex CLI settings). Test the path with twira notify test (or twira notify speak-test). Edit preferences in the dashboard at /notifications, one /ar-dash away.
One install. Your agent will know the difference in the first session.
$ curl -fsSL twira.com/install.sh | sh