# Wire Codex CLI into your menu bar

Codex CLI has a first-class `notify` hook that fires on every turn-complete event with a JSON payload. Pipe it to Lounge's listener and you'll know the instant a long turn finishes.

## One-click setup

### Skip the manual steps

Copy a ready-made prompt and paste it into any AI coding agent — Claude Code, Codex, Gemini, Cursor, or Aider. It detects your CLI and wires Lounge up for you.

## What you'll see

```plaintext
lounge_project · agent-turn-complete
Codex finished
Applied refactor across 3 files and ran tests.
codex · just now
```

## Step 1 — Enable the Monitor in Lounge

1. Right-click the Lounge icon in the menu bar and pick **Settings**.
2. Open the **Monitor** tab.
3. Toggle **HTTP listener** on. Optionally enable the unread badge and auto-open.

The Monitor tab and the listener itself only become active with a valid Lounge Pro license. The toggle is a no-op until you activate one in Settings → License.

## Step 2 — Smoke-test the listener

Before touching your AI agent, confirm the listener accepts a request. Run this in any terminal — you should see a new row appear in the LoungePanel.

```bash
curl -X POST http://127.0.0.1:8866/notify \
  -H 'Content-Type: application/json' \
  -d '{"title":"Hello from curl","body":"Lounge is listening","source":"smoke-test","level":"info","project":"setup","event":"smoke-test","status":"complete"}'
```

## Step 3 — Drop in the notify helper script

Codex calls any program listed in `notify` with a single JSON argument. This helper parses the payload, extracts `type` and `last-assistant-message`, and POSTs to Lounge.

```bash
#!/usr/bin/env bash
# ~/.local/bin/lounge-notify-codex
# Invoked by Codex CLI with a single JSON argument.
# See: https://lounge.app/tutorials/codex-cli

set -euo pipefail

payload="${1:-}"
[ -z "$payload" ] && exit 0

type=$(printf '%s' "$payload" | jq -r '.type // "event"')
last=$(printf '%s' "$payload" | jq -r '."last-assistant-message" // ""' \
        | head -c 240)
project=$(basename "$PWD")

case "$type" in
  agent-turn-complete)
    title="Codex finished"
    status="complete"
    level="info"
    ;;
  *)
    title="Codex: $type"
    status="complete"
    level="info"
    ;;
esac

jq -nc \
  --arg title "$title" \
  --arg body "${last:-Turn complete}" \
  --arg level "$level" \
  --arg project "$project" \
  --arg event "$type" \
  --arg status "$status" \
  '{title:$title, body:$body, source:"codex",
    level:$level, project:$project, event:$event, status:$status}' \
  | curl -s -X POST http://127.0.0.1:8866/notify \
      -H 'Content-Type: application/json' -d @- >/dev/null || true
```

Save and make it executable:

```bash
mkdir -p ~/.local/bin
# paste the script from Step 3 into this file:
$EDITOR ~/.local/bin/lounge-notify-codex
chmod +x ~/.local/bin/lounge-notify-codex
```

## Step 4 — Register the script in `config.toml`

Add a `notify` key at the top level of `~/.codex/config.toml`. Use the absolute path — Codex does not expand `~`.

```toml
# ~/.codex/config.toml
notify = ["/Users/you/.local/bin/lounge-notify-codex"]
```

Replace `/Users/you` with your actual home path (check with `echo $HOME`).

## Step 5 — Try it

Start Codex, ask it to do something non-trivial, and wait for the turn to end. A new row should appear in the LoungePanel with the `codex` source and a green "complete" dot.

## Troubleshooting

### Nothing shows up in Lounge

Confirm Settings → Monitor is enabled and your license is active. The listener silently refuses to start without a valid license, even if the toggle is on.

### Port 8866 already in use

Another process is bound to 8866. Find it with `lsof -iTCP:8866 -sTCP:LISTEN` and stop it. The port is fixed in the current build.

### Connection refused from the CLI

The listener only binds to 127.0.0.1. If your agent runs in a container or VM, forward the port or use `host.docker.internal:8866` instead of localhost.

### Codex runs the command but nothing hits Lounge

Run the helper by hand with a fake payload: `~/.local/bin/lounge-notify-codex '{"type":"agent-turn-complete","last-assistant-message":"hello"}'`. If that works, double-check the absolute path inside your `notify = [...]` array — Codex does not expand `~`.

### Wrong schema keys

Codex payload field names use hyphens (`last-assistant-message`, `turn-id`). Make sure your jq query matches — hyphenated keys need `."last-assistant-message"` quoting.
