# Attention Hook Setup

CodexBar receives agent lifecycle events through:

```text
POST http://127.0.0.1:7842/attention
```

The shared hook forwarder is:

```text
companion/attention_hook.py
```

It reads the hook JSON from stdin and posts only the fields CodexBar needs: provider, event name, session id, and current working directory.

## Before Enabling Hooks

Start the companion server:

```bash
python3 companion/server.py
```

Test the forwarder manually:

```bash
printf '{"hook_event_name":"PermissionRequest","session_id":"manual","cwd":"%s"}' "$PWD" \
  | python3 companion/attention_hook.py Codex

curl http://127.0.0.1:7842/status
```

Clear the manual test state:

```bash
printf '{"hook_event_name":"SessionEnd","session_id":"manual","cwd":"%s"}' "$PWD" \
  | python3 companion/attention_hook.py Codex
```

## Codex

Codex discovers hooks from locations such as:

```text
~/.codex/hooks.json
~/.codex/config.toml
<repo>/.codex/hooks.json
<repo>/.codex/config.toml
```

For machine-wide CodexBar attention tracking, add this to:

```text
~/.codex/hooks.json
```

Replace `/Users/jameslopez/projects/CodexBar-ESP32` if the repo moves.

```json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume|clear|compact",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py\" Codex",
            "timeout": 5,
            "statusMessage": "Updating CodexBar"
          }
        ]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py\" Codex",
            "timeout": 5,
            "statusMessage": "Updating CodexBar"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py\" Codex",
            "timeout": 5
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py\" Codex",
            "timeout": 5
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/usr/bin/python3 \"/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py\" Codex",
            "timeout": 5
          }
        ]
      }
    ]
  }
}
```

Codex may require hook trust review. Use `/hooks` in Codex to inspect and trust the hook definition.

### Codex App Notify Fallback

Some Codex app builds invoke the `notify` command reliably but do not appear to invoke `~/.codex/hooks.json` lifecycle hooks. For those builds, wrap the existing notify command with CodexBar:

```toml
notify = ["/usr/bin/python3", "/Users/jameslopez/projects/CodexBar-ESP32/companion/codex_notify.py", "--", "/path/to/existing/notifier", "turn-ended"]
```

The wrapper posts a short-lived Codex `Notification` attention event, then forwards stdin to the existing notifier command. Notification attention expires quickly on the companion so completed Codex turns do not leave a stale bar up for an hour.

## Claude Code

Claude Code hooks can be configured globally at:

```text
~/.claude/settings.json
```

For project-local experiments, use:

```text
.claude/settings.local.json
```

Add or merge this `hooks` object. Replace `/Users/jameslopez/projects/CodexBar-ESP32` if the repo moves.

```json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume|clear|compact",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5,
            "statusMessage": "Updating CodexBar"
          }
        ]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5,
            "statusMessage": "Updating CodexBar"
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "permission_prompt|idle_prompt|elicitation_dialog",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5
          }
        ]
      }
    ],
    "Elicitation": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/Users/jameslopez/projects/CodexBar-ESP32/companion/attention_hook.py", "Claude"],
            "timeout": 5
          }
        ]
      }
    ]
  }
}
```

## Notes

- The hook forwarder exits `0` even if CodexBar is offline, so it should not block Claude or Codex.
- Hook commands use a two-second HTTP timeout.
- CodexBar uses `SessionEnd` to clear state when available, but stale records also expire on the companion.
- `Stop` currently maps to `done`, not `needs_user`.

## Sources

- Claude Code hooks reference: https://code.claude.com/docs/en/hooks
- Codex hooks reference: https://developers.openai.com/codex/hooks
