Desktop notifications for Command Code: know when the agent needs you or finishes a run while you work in another application.
Published as-is, not actively maintained. Issues and pull requests are welcome but may not get a response, and security reports are not handled. It is MIT licensed: fork it, fix it, and republish it freely.
Beta. This mod depends on Command Code's experimental Mods API, which may change and break compatibility. It was tested on macOS and Linux desktops with Command Code 1.82. Native Windows delivery is implemented but untested; if it works or fails for you, an issue saying so helps the next person.
Requires Command Code and Node.js 22.6 or newer. Install the mod through Command Code's package manager, which also installs its notification dependency. There is no separate build or custom installer.
cmd mods add -g command-notify@beta
cmdThe package includes terminal-notifier through its node-notifier dependency.
If alerter is already installed it takes priority; otherwise the bundled
helper is used, with macOS's osascript as a final fallback. No Homebrew package
is required for the default installation. Allow the notification sender in
System Settings → Notifications, and check Focus settings if banners are hidden.
In PowerShell:
cmdc mods add -g command-notify@beta
cmdcWindows uses cmdc, because cmd is the Windows command shell. See
Command Code on Windows.
The matching SnoreToast helper ships through node-notifier; no PowerShell
notification script or separate helper download is required. Enable notifications
for its sender in Windows Settings and check Do not disturb.
Windows ARM64 and Windows toasts from WSL are not supported by this beta.
The helper's default application identity must work on the desktop; that behavior
still needs real Windows verification. Leave windowsAppId at null unless you
already have a registered application identity. The mod does not register a
custom identity or create a branded Start Menu shortcut.
Install notify-send if it is missing, using your distribution's package manager:
# Debian / Ubuntu
sudo apt install libnotify-bin
# Fedora
sudo dnf install libnotify
# Arch Linux
sudo pacman -S libnotifyThen, from a terminal inside your desktop session:
cmd mods add -g command-notify@beta
cmdA working desktop notification service is required. X11 and Wayland environments are supported by the delivery path, but actual desktop behavior remains unverified. SSH, containers, and WSL are outside this beta's supported scope; notifications are not forwarded to another machine or to the Windows host.
-g installs for your user across projects. Omit it to install only for the
current Git project; project mods load after the workspace is trusted. Restart
any existing Command Code session after installation.
To refresh the beta source:
cmd mods updateOn Windows use cmdc mods update. This command updates/reconciles configured mod
sources, not just this mod. To pin a release instead, install an exact version such as
command-notify@1.0.0-beta.3 in place of command-notify@beta.
Chat normally in Command Code, then switch to another application. There is no separate notification test step. The first session that creates the settings file shows a non-blocking notice with its location.
A notification is titled Command Code and identifies the session by its title, or the project folder name before a title exists. Linux includes that context in the body because its helper has no subtitle field.
| Event | What to expect |
|---|---|
| Agent asks a question | Needs your input in interactive sessions. |
| Agent requests permission | Needs approval: <tool>, with risk information when supplied. |
| Run finishes | Finished with a short result excerpt when available. |
| Turn limit or mod stop hook ends a run | Stopped at the turn cap or Stopped early (mod). |
| Run fails | Failed: <message>. |
| Interruption | An interruption notification when the host's event path reports one; duplicate outcomes are suppressed. |
Question and permission alerts rely on events from the interactive Command Code UI. Headless runs can report outcomes, but do not expose the same prompt events. Background sub-agent completions are not separately announced. Pending alerts are removed or replaced where the backend supports it; completion alerts are left in the desktop's control. Bodies are shortened to about 150 characters. Notifications can contain project names, result excerpts, tool names, and error text; your OS may show those on the lock screen.
Delivery, sounds, expiry, and visibility depend on OS permissions, Focus/Do not disturb, desktop policy, and the selected helper. A successfully started helper cannot prove a banner appeared. Notification failures should produce a concise notice in Command Code, with the settings path and a recovery step, without interrupting the agent's work. Repeated identical problems are reported once per loaded mod instance.
Settings are per user, even when the mod is installed for one project:
| Platform | File |
|---|---|
| macOS / Linux | ~/.commandcode/notify.json |
| Windows | %USERPROFILE%\.commandcode\notify.json ($HOME\.commandcode\notify.json in PowerShell) |
The mod creates the file with defaults when it first loads. Existing files are preserved. Edit it in any text editor; settings are reread for each notification. Use valid JSON, without comments. Missing fields keep their defaults. An invalid field uses its default and produces a warning; unreadable or malformed JSON uses the last valid settings, or defaults, and is never silently overwritten.
{
"enabled": true,
"backend": "auto",
"questionFallback": "off",
"questionText": "generic",
"focusTerminalOnClick": true,
"suppressWhenTerminalFocused": false,
"replacePendingNotifications": true,
"clearOnResolve": true,
"quietHours": {
"enabled": false,
"start": "22:00",
"end": "08:00",
"bypassEvents": []
},
"debug": false,
"debugVerbose": false,
"alerterPath": null,
"windowsAppId": null,
"events": {
"question": {"enabled": true, "sound": "Submarine", "timeout": 0},
"permission": {"enabled": true, "sound": "Submarine", "timeout": 0},
"done": {"enabled": true, "sound": "Glass", "timeout": 10},
"error": {"enabled": true, "sound": "Basso", "timeout": 10}
}
}| Setting | Meaning |
|---|---|
enabled |
Enable or disable all notifications. |
backend |
auto (recommended), alerter, terminal-notifier, osascript, notify-send, or snoretoast. An unavailable choice warns and falls back to this platform's automatic order. |
events.<event>.enabled |
Enable each of question, permission, done, and error independently. |
events.<event>.sound |
macOS sound name or none. Windows maps any name to its default notification sound; Linux sound selection is unsupported. |
events.<event>.timeout |
Requested seconds until dismissal. 0 passes no explicit timeout; it does not guarantee a persistent banner. Windows and osascript ignore this setting; Linux/macOS desktop policy may override it. |
questionFallback |
off or tool_queued. The latter uses queued ask-tool events if a host version does not deliver question interaction events. It never enables itself. |
questionText |
generic (recommended) or heuristic. Heuristic text can associate the wrong question header because host events lack correlation IDs. |
focusTerminalOnClick |
macOS only: bring the terminal that raised a notification forward when you click it. No effect on Linux or Windows. See Click to focus. |
suppressWhenTerminalFocused |
macOS only: suppress alerts while a recognized terminal is frontmost. A failed focus lookup allows delivery. |
replacePendingNotifications |
Replace earlier pending alerts and earlier outcomes from the same run when supported. Outcomes from different runs are retained. |
clearOnResolve |
Attempt to clear question/permission alerts after resolution. Run settlement always attempts to clear pending alerts, even when this is false. Removal is best effort. |
quietHours.enabled |
Enable scheduled suppression. |
quietHours.start / end |
Local 24-hour HH:MM; start inclusive, end exclusive. Overnight windows work; equal times suppress nothing. |
quietHours.bypassEvents |
Event classes allowed through quiet hours, such as ["error"]. Does not bypass global disablement. |
alerterPath |
macOS executable path override, or null to search PATH. |
windowsAppId |
Already registered Windows application identity, or null for the helper's default. |
debug |
Write diagnostic metadata to notify-debug.log beside the settings file. Off by default. |
debugVerbose |
With debug, include helper arguments and notification text in that log. Off by default; avoid sharing verbose logs unredacted. |
These commands save to the same user settings file:
Plain /notify shows the settings file location and available settings commands.
| Command | Effect |
|---|---|
/notify on / /notify off |
Enable or disable notifications. |
/notify backend auto |
Restore automatic backend choice and reset failure tracking. A specific backend name is also accepted. |
/notify sound done none |
Silence completion alerts; substitute another event or sound name. |
/notify timeout done 10 |
Request a ten-second completion banner; off passes no timeout. |
/notify quiet-hours on 22:00 08:00 |
Enable an overnight quiet window. |
/notify quiet-hours off |
Disable quiet hours. |
Invalid command arguments change nothing. Setters refuse to overwrite malformed
JSON. A lock prevents simultaneous sessions from overwriting each other's edits;
if a write cannot obtain it, a notice explains the failure. Remove a leftover
notify.json.lock only after closing all Command Code sessions that may write it.
Command Code's --mod-option flags override the file for that session:
cmd --mod-option enabled=false
cmd --mod-option sound=noneUse cmdc on Windows. Available flags are enabled=true|false, backend=<name>,
sound=<name|none>, timeout=<seconds|off>, and debug=true|false. Sound and timeout
flags affect every event class. A settings command tells you when a launch flag
still overrides the saved value. Flag names are shared with other mods; prefer
the JSON file if another mod uses these names.
| Platform/helper | Sound | Expiry | Clear pending alert | Click to terminal |
|---|---|---|---|---|
macOS: alerter |
Named or silent | Requested | Best effort | Yes, while the session runs |
macOS: bundled terminal-notifier |
Named or silent | Requested | Best effort | Yes |
macOS: osascript fallback |
Named or silent | OS-controlled | No | No |
Linux: notify-send |
No selection | Desktop may ignore | No | No |
| Windows: bundled SnoreToast | Default or silent | OS-controlled | Best effort | No |
macOS automatic order is alerter → terminal-notifier → osascript.
Linux uses notify-send; Windows uses the helper matching the running Node.js
architecture (x64 or ia32). Helpers for other platforms are never executed.
Linux notifications escape markup characters; rendering may differ by desktop.
Some macOS helpers can remain alive while waiting for interaction. Each loaded mod
limits sticky helpers to 16; admitting another stops the oldest first, which may
end its banner. If it cannot stop, the new helper is refused. Bounded helper
operations can only be stopped while the Command Code session is still running.
Click to focus is macOS only. With focusTerminalOnClick on (the default),
clicking a notification's body brings forward the terminal or editor the
Command Code session runs in. On Linux and Windows the setting has no effect;
clicking a notification there does whatever the desktop does by default.
| Helper | Click detected by | What is raised | Status |
|---|---|---|---|
alerter |
@CONTENTCLICKED on its output |
iTerm2: the session's own window/tab/split (AppleScript, ITERM_SESSION_ID); Terminal.app: the tab on the session's tty; other terminals: the application via open -b |
Implemented; application activation checked, exact window selection awaiting real-click verification |
bundled terminal-notifier |
the helper itself (-activate) |
the application | Works |
osascript fallback |
— | — | Not supported: clicking opens Script Editor (macOS behavior) |
The terminal is identified from __CFBundleIdentifier (the app that launched
the session), falling back to a recognized TERM_PROGRAM. Known limits:
- With
alerter, the click is reported back to the running session, so a click after the session has exited, or from Notification Center after the banner has closed, does nothing. - For terminals other than iTerm2 and Terminal.app, and with
terminal-notifier, the whole application is activated, so macOS raises its most recently used window, which may not be the session's. - Selecting the exact iTerm2 or Terminal.app window uses AppleScript, so macOS may ask once whether to allow automating that terminal. If you decline, or the script fails or does not finish within 10 seconds, the application is activated instead.
- In
tmuxattached from a different terminal,__CFBundleIdentifiercan name the wrong application. Sessions over SSH with an unrecognizedTERM_PROGRAMget no click action.suppressWhenTerminalFocusedusesTERM_PROGRAMonly.
- Nothing appears: check
enabled, the relevant event'senabled, quiet hours, and OS notification permissions/Focus. Continue a normal conversation with Command Code and watch for its failure notice. Silent OS suppression may produce no helper error. - Linux helper missing: install the libnotify package above and run from a
terminal in your logged-in desktop session. A headless environment does not
become a desktop merely by installing
notify-send. - Windows silent delivery: check Windows notification settings and the helper's
sender identity. Keep
windowsAppId: nullunless you know the configured identity is registered. Report the OS, Node architecture, Command Code version, and any failure notice; Windows desktop delivery is still awaiting beta verification. - Helper missing or cannot start: reinstall the mod through Command Code's package manager, check executable permissions/security software, and restart.
- Helper marked unhealthy: correct the reported problem, then restart Command
Code or use
/notify backend auto. Later notifications skip failing helpers; already submitted notifications are not reposted automatically. - Invalid settings: repair the JSON file at the path in the notice. Rename it if you want to preserve it while allowing defaults to be recreated next session.
- Question alerts missing after a host update: try
questionFallback: "tool_queued"in the settings file. Generic question text is safest. Mods API changes may require a new mod release. - Need diagnostic detail: temporarily set
debug: true, reproduce through normal conversation, and inspectnotify-debug.logbeside the settings file. Standard diagnostics omit notification bodies but may include local paths and identifiers. Review and redact logs before sharing them.
Close running Command Code sessions, then remove the same source and scope used at installation. For the global beta installation above:
macOS / Linux:
cmd mods remove -g command-notify@betaWindows PowerShell:
cmdc mods remove -g command-notify@betaFor project installation, omit -g and run inside that project. If you installed
an exact version, use that version instead of @beta. Restarting ensures the mod
is no longer loaded. Removing a package does not dismiss every existing OS banner.
Settings and diagnostics are intentionally retained so a reinstall preserves preferences. To remove them too, delete only these files after closing sessions:
macOS / Linux:
rm -f "$HOME/.commandcode/notify.json" "$HOME/.commandcode/notify-debug.log" "$HOME/.commandcode/notify.json.lock"Windows PowerShell:
Remove-Item -LiteralPath "$HOME\.commandcode\notify.json", "$HOME\.commandcode\notify-debug.log", "$HOME\.commandcode\notify.json.lock" -ErrorAction SilentlyContinueDo not delete the whole .commandcode directory: it contains other Command Code
settings. OS notification history is cleared separately in the notification center.
Any custom Windows identity you registered manually must also be removed manually.
On Windows, the bundled SnoreToast 0.7.0 also creates artifacts outside
.commandcode. With the default application identity, these include:
%APPDATA%\Microsoft\Windows\Start Menu\Programs\SnoreToast\0.7.0\SnoreToast.lnk.HKCU\SOFTWARE\Classes\CLSID\{eb1fdd5b-8f70-4b5a-b230-998a2dc19303}\LocalServer32, which points to the bundled SnoreToast executable.- Extracted icon files under
%TEMP%\snoretoast\0.7.0\.
Before removing the package, inspect the shortcut target and the registry entry's value and record whether they point into this mod's dependency installation. After closing sessions, remove only that shortcut and that CLSID registration if this installation created them and no other application uses them. Remove only the extracted files belonging to this helper version from the temporary directory; leave other versions alone. Do not remove shared SnoreToast registrations or shortcuts: other applications may depend on the same identity. If ownership is uncertain, leave the shared artifacts in place.
The mod itself sends no network requests and needs no API keys. Notification text
is handed to local OS helpers. Debug logging is opt-in; verbose logging can store
conversation excerpts. Runtime settings and logs live outside this repository.
SnoreToast also emits notification XML, including title and message text, to the
Windows debug output channel (OutputDebugStringW). This native-helper output is
independent of the mod's debug and debugVerbose settings and can be captured by
debugging tools even when both settings are off.
MIT; see LICENSE. Third-party helpers and dependencies retain their own licenses, supplied with those packages. Publication steps are in RELEASING.md.