Use an Elgato Stream Deck Neo as a Codex Micro for the ChatGPT desktop app. The app sees a virtual Codex Micro over a local shim: agent keys light up with task state, actions map to Codex commands, and the Neo info bar shows overflow agents.
Primary target: Stream Deck Neo (10 controls: 8 LCD keys + 2 touch keys + info bar). Stream Deck + still works with dials.
Fork of mpociot/codex-micro-stream-deck-emulator with Neo-first layouts, host-aware UI, and a Main launcher strip.
Not affiliated with OpenAI, Work Louder, or Elgato. Trademarks belong to their owners. Personal interoperability project. See Legal.
| Keys | Role |
|---|---|
| Top row (4) | Agent slots 0–3 (task colors + center dot) |
| Bottom row | MIC (push-to-talk), Approve, Reject, Click |
| Left / right touch | Reasoning depth down / up |
| Info bar | Overflow agents 5–6, or status text |
Hold on agent keys (fires at 400 ms while still held, so ChatGPT reacts immediately):
| Agent slot | Hold sends | Suggested app assignment |
|---|---|---|
| 0 | ACT06 |
NEW (newTask) in Codex Micro settings |
| 1 | ACT09 |
SPLIT / fork (default) |
| 2 | ACT12 |
DEL / archive (reassign from submit if you want) |
| 3 | (none) | tap only |
Quick tap still selects the agent.
| Mode | When | What you see |
|---|---|---|
| Micro | ChatGPT shim connected | Full Codex layout above |
| Main | No host, or you leave Micro | App launcher strip |
- Hold bottom-right key (Neo: CLICK, last key of row 2) ≥ 400 ms → Main (host stays connected).
- Tap ChatGPT on Main while host is live → back to Micro (does not relaunch the app).
- Quick tap CLICK in Micro still sends encoder click (
ENC_CLK).
Top row when offline / on Main:
| Key | Action |
|---|---|
| ChatGPT | Launch with shim (./shim/launch-chatgpt.sh), or return to Micro if already connected |
| Claude | open -a Claude |
| Gemini | open -a Gemini |
| Ghostty | open -a Ghostty |
- Real macOS app icons (from the
.appbundle). - Green LED (Stream Deck style) bottom-right when that app is running.
- Info bar:
Waiting for ChatGPTorMain · GPT = Micro.
- Shim mode (default for login service): deck shows Micro while the shim socket is open; Main launchers when the shim disconnects. No false offline after ChatGPT stops polling.
- Helper mode: host presence follows RPC idle timeout (virtual HID stays up alone).
- Stream Deck + mapping with Think / Talk / Submit dials (original upstream).
- Optional login LaunchAgents so the bridge and ChatGPT watcher start at
login (
scripts/install-login-service.sh). - Keyboard input for testing without hardware:
--input keyboard.
- macOS
- Node.js ≥ 18
- Elgato Stream Deck (Neo recommended; Plus supported)
- ChatGPT desktop app with Codex Micro
npm installRun a bridge and launch ChatGPT with the shim (normal Dock open will not load the virtual device).
1. Start the bridge:
node bin/codex-micro-emulator.js --mode shim2. Launch ChatGPT with the shim:
./shim/launch-chatgpt.shThis quits any running ChatGPT, waits for it to exit, then relaunches with the shim. The app should detect a Codex Micro and the Neo should paint the Micro UI.
The shim injects a small module at launch (no app files modified). Personal use only; may break when ChatGPT updates. Helper mode (Apple entitlement) is documented in DEVELOPMENT.md.
Without a Stream Deck:
node bin/codex-micro-emulator.js --mode shim --input keyboard./scripts/install-login-service.sh
# later:
./scripts/uninstall-login-service.shInstalls LaunchAgents for the bridge (shim mode) and a watcher that relaunches ChatGPT with the shim if it was opened unshimmed.
┌──────────┬──────────┬──────────┬──────────┐
│ Agent 0 │ Agent 1 │ Agent 2 │ Agent 3 │ hold 0/1/2 → actions
├──────────┼──────────┼──────────┼──────────┤
│ MIC │ APPR │ REJ │ CLICK │ hold CLICK → Main
└──────────┴──────────┴──────────┴──────────┘
[ − reason ] info bar [ + reason ]
Assign tasks in Codex Micro settings → Agent keys (recent / priority / pinned / custom). Colors:
| State | Color |
|---|---|
| idle | white |
| thinking | blue |
| complete | green |
| needs input | amber |
| error | pink |
Neo shows four agent keys; slots 5–6 appear on the info bar.
Wire ACT06 / ACT12 in the app if you want hold → new task / archive. Defaults
often leave ACT06 = Fast.
- Top row: agents 0–3
- Bottom: Fast / Approve / Reject / Split
- Dials: Think (rotate), Talk (press), Submit (press)
- Same Main / Micro behavior on the 2×4 grid when the host is up
| Symptom | Try this |
|---|---|
| ChatGPT does not detect the device | Start the bridge first, then ./shim/launch-chatgpt.sh. Dock launch skips the shim. |
| Neo stays on launchers while app says Connected | Restart the bridge; shim open should force Micro UI. Check bridge.log. |
Keys / colors hang, app logs TIMEOUT |
Restart bridge, relaunch ChatGPT with the shim. |
| Agent keys stay cream | Assign tasks in Codex Micro settings. |
| Hold does Fast instead of New task | In the app, reassign action slot ACT06 to NEW. |
| No icons | Re-run npm install (sharp, lucide-static). |
| Input Monitoring not granted | System Settings → Privacy → Input Monitoring → allow ChatGPT. |
Verbose bridge: add --verbose. Shim log: shim.log.
| What | Where |
|---|---|
| Neo / Plus key map, holds | src/mapping.js |
| Main launcher apps | src/streamdeck.js (OFFLINE_LAUNCHERS), src/app-icons.js |
| Keycap icons / catalog | src/keycaps.js, assets/icons/ |
| Agent colors | src/states.js |
| Hold / host idle thresholds | HOLD_MS, HOST_IDLE_MS in src/streamdeck.js |
Protocol details, helper mode, and architecture: DEVELOPMENT.md.
npm testBased on the upstream Stream Deck + emulator by Marcel Pociot.
For interoperability and personal use by people who already own the
hardware. Ships no OpenAI, Work Louder, or Elgato code or assets: independent
protocol reimplementation plus open Lucide icons where
needed. App logos on the Main strip are read from your installed .app bundles
at runtime. Trademarks belong to their owners. MIT licensed; use at your own
risk.
