A small native macOS menu bar app. One compiled Swift executable, AppKit and Foundation only, with no third-party dependencies or runtime scripts.
The dot reflects all loaded sessions on your shared Codex app-server, including child sessions:
| Color | Meaning |
|---|---|
| Red | At least one session needs approval or interactive input |
| Yellow | At least one session is working, and none needs input |
| Green | No session needs input or is working (including zero sessions) |
| Gray | Connecting, disconnected, or unable to read status |
Finished sessions waiting for your next prompt count as idle/green. Red means Codex has an outstanding approval or input request. Click the dot for counts, reconnect, and quit.
While red or yellow, the entire menu bar also gets a matching translucent tint. The tint disappears when green or disconnected. It is click-through and cannot take keyboard focus, so menus and the status button still work. It follows display and Space changes, includes notched displays, and hides when macOS reports the menu bar hidden. With separate Spaces per display enabled, each display is tinted. This is a 32% opacity overlay, rather than a system theme change: macOS's existing text and icons remain visible through the color, and their appearance is tinted too.
Requires macOS 13+ and Swift 6+ (Apple's Command Line Tools). Builds for the current Mac's architecture.
sh scripts/build.sh
open dist/falcon-notifier.appThe release app is self-contained; you can copy dist/falcon-notifier.app to
~/Applications. For automatic startup, add that copy under System Settings →
General → Login Items. There is no Dock icon or main window.
Requires the Codex CLI with app-server --listen and --remote support.
falcon-notifier connects to a separately running server; it doesn't start or stop
one. By default it observes ws://127.0.0.1:45999.
Start the server in a dedicated terminal and leave it running:
codex app-server --listen ws://127.0.0.1:45999In another terminal, switch to your project directory and start a session on that server:
codex --remote ws://127.0.0.1:45999 --cd "$PWD"To resume an existing session instead:
codex --remote ws://127.0.0.1:45999 --cd "$PWD" resumeKeep the server running while using Codex and falcon-notifier. If the server is unavailable, the dot is gray and the notifier retries automatically. Adding the notifier to Login Items starts only the notifier; start the server separately. Sessions on other servers or standalone CLI processes aren't visible here.
To override the endpoint, pass --server or set CODEX_APP_SERVER_URL in the
launching process's environment. A Finder launch doesn't inherit your shell's
environment. For example:
open dist/falcon-notifier.app --args --server ws://127.0.0.1:45999node scripts/integration-test.mjs
dist/falcon-notifier.app/Contents/MacOS/falcon-notifier --once--once prints one JSON status and exits (nonzero when unavailable); --watch
prints changes. The integration test needs Node 18+ only for its local fixture,
and tests the compiled release executable without touching real Codex sessions.
It covers both approval and input waits, priority across sessions, pagination,
updates and closures during a snapshot, missed notifications, and reconnection.
CodexSource is a read-only WebSocket JSON-RPC client. It initializes a connection,
enumerates thread/loaded/list with pagination, and reads each loaded thread's
status without turns. It handles thread/status/changed immediately and
reconciles every 30 seconds to discover sessions and recover missed events.
New notifications take precedence over an in-flight snapshot. Requests time out
after ten seconds; failed connections retry after five seconds. The server may
retain idle threads after a terminal closes; these remain green.
The observer never resumes threads or answers approval requests. The protocol is documented in Codex App Server. That interface is experimental, so future Codex updates may require adjustments.
The menu bar renderer consumes an Indicator (level, summary, SF Symbol name)
from a StatusSource. To add another signal later, implement that small protocol
and select it in main.swift, or compose multiple sources into one indicator.
Codex state and networking are separate from the AppKit presentation.
SwiftBar could also host a persistent compiled plugin. This app keeps the installation to a single native process.