Control the Codex, Claude, Hermes and ZCode desktop apps from a Logitech MX Creative Console on macOS: pick a session on the keypad, see which sessions need you on the Home page, prepare model and effort with the dials, stop or compact a run, approve a request, dictate a message, or toggle Codex Voice Chat. A Utilities page opens your everyday apps and sites, and an optional Discord page exposes mute, deafen, leave-voice and a soundboard.
Everything runs locally. The Logi plugin talks to a small Node.js daemon over a private Unix socket; the daemon talks to the apps through their own local interfaces (IPC socket, local gateway, SQLite metadata, Accessibility). Nothing is sent over the network.
Status: 0.2.0, first public release. It is the author's daily-driver setup, extracted and anonymised. It has been verified on one Apple Silicon Mac (macOS 26, Logi Plugin Service 6.4). Treat other configurations as untested and read Compatibility before installing.
- What it does
- Capabilities per app
- Requirements
- Install
- Permissions
- Using the console
- Utilities
- Discord
- Icons
- Codex shortcuts, Claude Code hooks and status line (optional)
- Data, storage and network
- Compatibility
- Limitations
- Troubleshooting
- Uninstall
- Building from source
- Repository layout
- License
| Home page | Codex session page | Utilities page |
|---|---|---|
![]() |
![]() |
![]() |
Demo renders produced by scripts/render-demo.mjs with fictional sessions.
- Home page (keypad): four app keys plus up to five live session cards per page, sorted by urgency: questions, approvals and blocked runs first, then running sessions, then finished results you have not looked at yet. Pressing a card opens that exact session in its app.
- Session lists: nine most recent sessions per page for the selected app. The big dial highlights a card, Apply opens it.
- Session page (Codex, Hermes, ZCode): model and effort keys, context-usage indicator, Stop, Compact (two-step confirmation), Yes for a single identified approval, Answer for Codex multiple-choice questions, Dictate, and for Codex a Speed toggle, Voice Chat toggle and Submit/Cancel after dictation.
- Dials: the small dial prepares the model, the big dial prepares the effort (or moves the selection on list pages). Green means confirmed in the app, orange means prepared, grey means unavailable. Apply commits prepared settings for the next request.
- Utilities page: the second key on the dialpad. Opens WhatsApp, Reddit, X, YouTube, Gmail, Zoho Mail and Google Calendar by default; fully configurable.
- Discord page (optional): voice controls and a soundboard for one server you configure.
- Menu-bar companion ("Agent Console.app"): shows the same state in a window, can restart the local connection and opens the Accessibility settings pane.
Derived from the daemon wiring in daemon/server.mjs and the adapters. "Console" means reachable from the physical keypad/dialpad.
| Capability | Codex | Claude (Desktop + Claude Code) | Hermes | ZCode |
|---|---|---|---|---|
| Discover recent sessions | Yes (local state DB + live IPC) | Yes (Desktop session metadata, sidebar, CLI registry) | Yes (local gateway + state DB) | Yes (task index DB + logs) |
| Open / select a session | Yes (deep link) | Yes (deep link, verified in the window) | Yes (sidebar) | Yes (sidebar) |
| Home notices (working / needs you / finished) | Yes | Yes (native sidebar state, hooks when installed) | Yes | Yes |
| Model / effort | Yes | Not on the console | Yes | Yes |
| Stop | Yes | Not on the console | Yes | Yes |
| Compact | Yes | Not on the console | Yes | Yes |
| Approve (Yes) | Yes | Hook decision path only (see below) | Yes | Yes (visible card) |
| Answer multiple-choice question | Yes | No | No | No |
| Dictation (hold Dictate) | Native shortcut (Ctrl+Shift+D), Submit/Cancel after release | Not on the console | Yes | Yes |
| Voice Chat toggle | Yes (start / cancel connecting / end) | – | – | – |
Claude: the console lists and opens Claude sessions and shows their activity on Home. Model, effort, Stop, Compact, dictation and approvals for Claude remain in the app. The daemon contains code for those actions, but it is intentionally not wired to the console because it has not been verified on real sessions. With the optional Claude Code hooks installed, permission requests from the Claude Code CLI appear on Home and can be answered there through the hook decision channel.
- macOS 14 or later on Apple Silicon (built and tested on macOS 26 / arm64; Intel builds are untested).
- Logi Options+ with Logi Plugin Service 6.4 or later, and an MX Creative Console (keypad and dialpad). The plugin also declares Loupedeck CT-family devices, but only the MX Creative Console layout has been used.
- Node.js 22+ (
nodeon the PATH when you run the installer; the path is recorded). - The apps you want to control, installed and signed in: Codex desktop, Claude desktop (with the Claude Code tab), Hermes desktop, ZCode desktop. Any subset works; missing apps simply show no sessions.
- To build from source: Xcode Command Line Tools (
swiftc) and the .NET SDK 10.
Two parts are needed: the Logi plugin (what Logi Plugin Service loads) and the local runtime (daemon, Accessibility helper, companion app, profiles). Both come from the same release.
-
Download
agent-console-<version>-macos-arm64.zipfrom the Releases page, verify it againstSHA256SUMS, and unzip it. -
In Terminal:
cd agent-console-<version> scripts/install.sh
The installer copies the runtime to
~/Library/Application Support/AgentConsole/, installs~/Applications/Agent Console.app, creates the plugin development link~/Library/Application Support/Logi/LogiPluginService/Plugins/AgentConsolePlugin.link, and installs the keypad and dialpad profiles as the default profiles of the "System" application for each device (the previous selection is recorded ininstallation.jsonand restored on uninstall). Use--dry-runto print every action first. -
Restart Logi Plugin Service: quit and reopen Logi Options+, or run
killall LogiPluginService. The plugin starts the daemon and the helper. -
Grant Accessibility to
AgentConsoleAXwhen macOS asks (see Permissions).
AgentConsole_<version>.lplug4 is the same plugin packaged for Logi Options+ / the Logi Marketplace. You can install it by double-clicking instead of using the link, but the runtime step (scripts/install.sh --skip-plugin) is still required, because the plugin launches daemon/server.mjs and PluginPackage/bin/AgentConsoleAX from the support directory.
git clone https://github.com/ozymandiashh/agent-console.git
cd agent-console
scripts/build.sh # npm ci, dotnet build, swiftc, companion app
scripts/install.sh| Permission | Who needs it | Why |
|---|---|---|
| Accessibility | AgentConsoleAX (launched by Logi Plugin Service) and optionally Agent Console.app |
Reads window titles, sidebars and controls of Claude, Hermes, ZCode and Discord, presses their buttons and menu items, types /compact into ZCode. Codex is driven through its IPC socket and deep links, not Accessibility. |
| Microphone | The target app, not Agent Console | Dictation and Voice Chat are started by pressing the app's own native controls; the console never records audio. |
| Full Disk Access | Not required | The daemon reads only the apps' own state files under your home directory. |
| Network | None | No listening TCP port and no outbound connections (the Hermes adapter connects to the Hermes app's own 127.0.0.1 gateway). |
macOS grants Accessibility to the helper only when it is launched by Logi Plugin Service. If you start AgentConsoleAX from a shell for testing, it will report trusted:false even after you enabled it. Let the plugin restart it (killall AgentConsoleAX is enough; the plugin relaunches it within seconds).
Keypad (nine LCD keys, left/right arrows) and dialpad (four keys, two dials).
Dialpad keys: Home (top left), Utilities (top right), Fast (bottom left, Codex speed), Apply (bottom right).
- Home: the four app keys, then session cards. Right arrow pages through cards. Pressing an app key opens its session list (and for Codex, Hermes and ZCode brings the app forward; Claude is listed passively and only comes forward when you open a session).
- Left arrow: back (session → list → apps). Right arrow: next page.
- Big dial: move the highlight on Home and lists; prepare effort on a session page; choose an answer on a question page. Eight units per step with a short debounce, so slow deliberate turns register as single steps.
- Small dial: prepare the model.
- Apply: open the highlighted card, commit prepared model/effort, or confirm Compact.
- Session page rows: model / effort / context (Codex: Speed) on top, Stop / Compact / Yes or Answer in the middle, and the bottom row for Voice / Speed / Dictate (Codex) or Dictate (Hermes, ZCode). After a Codex dictation the bottom row becomes Submit / Cancel / Dictate until you decide.
- Stop asks the app to interrupt the selected session. Compact shows CONFIRM in orange; press again (or Apply) within 10 seconds to run it.
- Dictate (Hermes, ZCode): hold until RECORDING, speak, release. The text stays in the app's composer for review; nothing is sent. Codex uses its native hold shortcut, with Submit and Cancel afterwards.
- Voice (Codex): starts Voice Chat in the selected task; pressing again cancels a pending connection or ends the call. The state is read from the app before each press.
- Key colours: purple pulsing = working, green tick = finished (unseen), yellow ? = needs you, orange = approval, red ! = blocked or error.
The Utilities page shows up to eight launchers (nine keys, the first is reserved for Discord when configured). Defaults:
| Key | Opens |
|---|---|
The WhatsApp app (net.whatsapp.WhatsApp) |
|
| https://www.reddit.com/ | |
| X | https://x.com/ |
| YouTube | https://www.youtube.com/ |
| Gmail | https://mail.google.com/ |
| Zoho Mail | https://mail.zoho.com/zm/ (use mail.zoho.eu, .in, … for your region) |
| Google Calendar | https://calendar.google.com/calendar/ |
URLs open in the default browser through /usr/bin/open; no shell is involved and repeated presses within a second are ignored.
To change the page, create ~/Library/Application Support/AgentConsole/utilities.json with an array of entries and restart the daemon (killall node is too broad; use the companion app's Restart connection or kill $(cat ~/Library/Application\ Support/AgentConsole/daemon.pid); the plugin relaunches it):
[
{"id": "notes", "name": "Notes", "color": "#ffcc00", "bundle": "com.apple.Notes"},
{"id": "docs", "name": "Team docs", "color": "#4285f4", "url": "https://docs.example.com/"},
{"id": "zohomail", "name": "Zoho Mail", "color": "#f4bc35", "url": "https://mail.zoho.eu/zm/"}
]Rules: id is lowercase letters, digits and dashes; exactly one of bundle (a macOS bundle identifier) or url (http/https); color is optional; at most eight entries. Invalid files stop the daemon with a clear error in daemon.log.
Discord controls are disabled unless ~/Library/Application Support/AgentConsole/discord-catalog.json exists. Copy assets/discord/catalog.example.json and fill in your server id and the sounds of its soundboard (Discord → server → soundboard; ids are visible in the app's developer mode). With a catalog, the first Utilities key opens a Discord page with Mute, Deafen, Exit voice and Soundboard; the soundboard plays sounds only in a voice channel of that server, after re-reading the channel before each press.
Key images are rendered by the daemon. The repository bundles original monogram icons (assets/*.png, generated by scripts/generate-icons.mjs) rather than third-party logos. To use your own artwork, place PNG files named after the tile in ~/Library/Application Support/AgentConsole/icons/ (for example icons/codex.png, icons/gmail.png, icons/<utility id>.png, icons/discord.png) and restart the daemon. Images are trimmed and fitted into 150×150 pixels.
These installers change files in your home directory and are therefore separate from install.sh. Each backs up what it changes.
node scripts/install-codex-bindings.mjsadds two app-scoped shortcuts to~/.codex/keybindings.json(composer.submit→ Ctrl+Alt+Shift+U,composer.clear→ Ctrl+Alt+Shift+Backspace) used by Submit/Cancel after dictation. The previous file is copied to~/Library/Application Support/AgentConsole/backups/composer-<timestamp>/. Restart Codex afterwards. Undo by restoring the backup.node scripts/install-claude-hooks.mjs --dry-run | --install | --uninstallregistershooks/agent-console-claude-hook.mjsin~/.claude/settings.jsonso Claude Code CLI sessions report state and permission requests to the daemon over the private socket, authenticated with a random secret stored inclaude-hooks.secret(mode 0600). Unrelated hooks are preserved;--uninstallremoves only the entries it added.node scripts/install-claude-statusline.mjs --dry-run | --install | --uninstallchains a small wrapper in front of your existing Claude Code status line so model and context usage reach the daemon; your own status line keeps working.
What the daemon reads (all read-only, all local, metadata only):
| App | Sources |
|---|---|
| Codex | ~/.codex/ipc/ipc.sock (the app's multi-client IPC), ~/.codex/state_5.sqlite (recent threads, via sqlite3 -readonly), ~/.codex/models_cache.json |
| Claude | ~/Library/Application Support/Claude/claude-code-sessions/**/*.json (Desktop session metadata), ~/.claude/sessions/*.json (CLI registry) and transcript file names/metadata under ~/.claude/projects/, the Claude window sidebar through Accessibility |
| Hermes | The Hermes app's local gateway on 127.0.0.1 (port discovered per launch, session token read from its own page), ~/.hermes/state.db |
| ZCode | ~/.zcode/v2/tasks-index.sqlite, ~/.zcode/cli/db/db.sqlite, ~/.zcode/cli/log/zcode-*.jsonl, ~/.zcode/v2/config.json, the ZCode window through Accessibility |
| Discord | The Discord window through Accessibility (voice state, soundboard panel) |
What it stores, in ~/Library/Application Support/AgentConsole/ (directory mode 0700, files 0600):
control.sock,gui.sock,daemon.pid: private sockets and pid.activity-ledger.json: per-session status and result identifiers so that a result you already opened is not announced again. No titles, no message text.session-actions.jsonl,dictation-events.jsonl,last-input.json: short operational logs (action, status, timestamps, daemon-generated messages).composer-review.json: Codex session ids with a dictated draft pending Submit/Cancel.claude-hooks.secret: the random bearer secret for the optional Claude Code hooks.daemon.log,plugin-status.log: process output.- Your configuration:
utilities.json,discord-catalog.json,icons/.
Session previews shown on Home (a short extract of a final answer or question) are held in memory only and truncated to about 200 characters. Full prompts, answers and tool output are never read into files.
Network: the daemon binds only a Unix socket. The only TCP connection it ever opens is to the Hermes app's own gateway on 127.0.0.1. There is no telemetry, no update check and no external request of any kind.
Observed working with the versions below on one Mac. Every adapter depends on internal interfaces (IPC protocol, SQLite schema, Accessibility labels) that the vendors can change without notice; a new app version can break discovery or a specific action until the adapter is updated. Accessibility labels are matched in English and Romanian.
| Component | Version observed |
|---|---|
| macOS | 26.6 (Apple Silicon) |
| Logi Plugin Service / Logi Options+ | 6.4.1 / 2.7 |
| Codex desktop (bundled in the ChatGPT app) | Codex framework 152.x, IPC protocol v3 |
| Claude desktop / Claude Code | 1.52 / 2.1.26x |
| Hermes desktop | 0.17.2 |
| ZCode | 3.11.2 |
| Discord | 0.0.410 |
| Node.js | 22 |
| .NET SDK (build only) | 10.0 |
- Claude actions other than open and Home notices are not on the console (see the capability table).
- Codex Submit and Cancel rely on the optional keybindings installer; without it those keys report the missing shortcut.
- Hermes and ZCode dictation depend on the apps' own dictation controls and on macOS Dictation being enabled for them.
- Free-text questions, secret prompts and MCP forms are answered in the app; the question page implements only Codex multiple-choice questions.
- The Discord soundboard catalog is static; changes on the server are not synced.
- Only one MX Creative Console (keypad + dialpad) layout is provided. The profiles are installed for the "System" application (they apply regardless of the foreground app).
- Hooks, keybindings and the status-line wrapper are per-user changes and must be uninstalled with the matching
--uninstallstep or the backups. - Not validated on a freshly installed Mac; the installer has been exercised against a temporary home directory and the built artifacts match the author's installed runtime byte for byte for the helper and the daemon.
- Keys stay dark or show "Starting…": the daemon is not running. Check
~/Library/Application Support/AgentConsole/daemon.logandplugin-status.log; make sureruntime.jsonpoints to an existing Node 22+ binary (scripts/install.shrewrites it). - "Enable Agent Console in macOS Accessibility": add
AgentConsoleAXin System Settings → Privacy & Security → Accessibility. If it is already listed, remove it, thenkillall AgentConsoleAXand let the plugin relaunch it. The companion app's Enable Accessibility… menu item opens the pane. - A session list is empty: the app is not running or not signed in, or its state files moved. The key shows the adapter's reason.
- Codex Submit/Cancel show a missing shortcut: run
node scripts/install-codex-bindings.mjsand restart Codex. - Profiles did not switch: connect each device once in Logi Options+ so its "System" profile folder exists, then rerun
scripts/install.sh --skip-plugin, or importAgentConsole-Keypad_<v>.lp5andAgentConsole-Dialpad_<v>.lp5from the release and select them in Logi Options+. - Blank key images:
sharpfailed to load (runnpm ciin the runtime directory or reinstall from the archive, which includesnode_modules).
scripts/uninstall.sh # keeps your configuration and metadata in the support directory
scripts/uninstall.sh --purge # also deletes ~/Library/Application Support/AgentConsoleThe uninstaller stops the daemon and helper, removes the plugin link, restores the previously selected profiles, removes the companion app and the runtime code, and runs the Claude hook/status-line uninstallers if they were used. It never touches the data of Codex, Claude, Hermes, ZCode or Discord; the only external file it can change is ~/.claude/settings.json (restoring your original hooks and status line). Restore ~/.codex/keybindings.json from the backup folder if you no longer want the two composer shortcuts. Finally remove AgentConsoleAX from the Accessibility list if you wish.
scripts/build.sh # PluginPackage/bin/*.dll, native/AgentConsoleAX, dist/Agent Console.app
npm test # 597 Node tests (they compile nothing and touch no real session)
dotnet run --project tests/native/NativeActionTests.csproj -c Release
dotnet run --project tests/gui-hold/GuiHoldTests.csproj -c Release
scripts/package.sh # dist/AgentConsole_<v>.lplug4, *.lp5 profiles, runtime zip, SHA256SUMSPluginApi.dll is taken from the installed Logi Plugin Service (LOGI_PLUGIN_API_PATH overrides the path) and is never copied into the package. logiplugintool (dotnet tool install --global LogiPluginTool) is used for packing and verification when available; otherwise the package is zipped directly. The Swift binaries are ad-hoc signed; the build is deterministic and the helper reproduces byte for byte with the same toolchain.
Plugin/ C# plugin for Logi Plugin Service (buttons, dials, hardware input, daemon bridge)
PluginPackage/ Package metadata (LoupedeckPackage.yaml, icon); bin/ is produced by the build
profiles/ Keypad (Loupedeck70) and dialpad (Loupedeck71) profiles
daemon/ Node.js daemon: controller, adapters, rendering, hooks control plane
native/ AXBridge.swift (Accessibility helper), AgentConsole.swift (companion app), console.html
hooks/ Claude Code hook script
scripts/ build, package, install, uninstall, optional installers, icon generator
assets/ Original monogram icons and the Discord catalog example
tests/ Node tests with synthetic fixtures; two small C# check programs
docs/ Architecture and privacy notes
MIT, see LICENSE. Third-party components and trademarks are listed in THIRD_PARTY_NOTICES.md.


