# Push to your iPhone when Claude Code needs input

> Get a push on your iPhone or Apple Watch when Claude Code asks for permission or finishes a task. Two Claude Code hooks and the honk CLI.

Source: https://honk-honk.app/guides/claude-code-notifications

Claude Code can work on its own for minutes at a time, then stop: it needs your permission to run a command, or it has finished and waits for your next prompt. If you’ve stepped away from the terminal, it waits as long as you do.

Claude Code has [hooks](https://code.claude.com/docs/en/hooks) for both moments. A `Notification` hook runs when it needs your permission, and a `Stop` hook runs when it finishes a response. This guide connects both to Honk, so your iPhone and Apple Watch tell you, and a session that pings ten times sends one notification instead of ten.

## Before you start

- A Honk account (invite-only for now: [request access](https://honk-honk.app/request-access)) and a project for your coding agents, such as “Claude Code”, with an ingestion key. Give this project its own key: anyone who has it can post to the project, and to nothing else.
- The `honk` CLI on the computer where Claude Code runs: `go install github.com/honk-hq/go/cmd/honk@latest`, or a binary from the [releases page](https://github.com/honk-hq/go/releases).
- `jq`, which reads the JSON that Claude Code passes to hooks. Recent versions of macOS include it; on Linux, install it with your package manager.

## 1. Keep the key in a file

Hooks run as shell commands in Claude Code’s environment. To keep the key out of settings files you might commit, put it in `~/.config/honk/env`:

```sh
HONK_URL=https://honk-honk.app
HONK_KEY=honk_…
```

Then run `chmod 600 ~/.config/honk/env`, so only you can read it.

## 2. Add the hook script

Save this as `~/.claude/hooks/honk.sh` and make it executable with `chmod +x`:

```bash
#!/usr/bin/env bash
# A push when Claude Code needs your permission (Notification) or finishes (Stop).
# Claude Code sends the event as JSON on stdin. Every ping from one project
# shares a group key, so Honk folds repeats into one notification.
set -a; . "$HOME/.config/honk/env"; set +a
input=$(cat)
dir=${CLAUDE_PROJECT_DIR:-$(jq -r '.cwd // empty' <<<"$input")}
project=$(basename "${dir:-$PWD}")

case $(jq -r '.hook_event_name' <<<"$input") in
  Notification)
    level=loud
    title="Claude Code needs you in $project"
    text=$(jq -r '.message // empty' <<<"$input") ;;
  Stop)
    level=light
    title="Claude Code finished in $project"
    text=$(jq -r '.last_assistant_message // empty | .[:280]' <<<"$input") ;;
  *) exit 0 ;;
esac

honk send --severity "$level" --title "$title" --message "${text:-$title}" \
  --group-key "claude-code/$project" --source "$(hostname -s)" --quiet || true
```

It reads the event that Claude Code sends on stdin and turns it into one Honk event:

- **Needs permission:** a Loud honk titled “Claude Code needs you in my-app,” with Claude Code’s own message, such as “Claude needs your permission.”
- **Finished:** a Light honk titled “Claude Code finished in my-app,” with the first 280 characters of the last reply.

`|| true` makes sure a network problem never turns into a hook error.

## 3. Register the hooks

Add both hooks to `~/.claude/settings.json`, which applies to every project on this computer. If the file already has a `hooks` key, add `Notification` and `Stop` next to the events that are already there:

```json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "$HOME/.claude/hooks/honk.sh",
            "async": true
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "$HOME/.claude/hooks/honk.sh",
            "async": true
          }
        ]
      }
    ]
  }
}
```

- `"matcher": "permission_prompt"` limits the `Notification` hook to permission requests. The `Stop` hook takes no matcher: it runs at the end of every response.
- `"async": true` runs the hook in the background, so Claude Code never waits for the push.

The same block works in a repository’s `.claude/settings.json`, which you can commit to share it with your team (each person then needs the script, the CLI and their own key), or in `.claude/settings.local.json` for one project on your computer only.

Type `/hooks` in Claude Code to check that both hooks are listed. To test the script without waiting for Claude, run:

```sh
echo '{"hook_event_name":"Notification","message":"Test from the terminal"}' | ~/.claude/hooks/honk.sh
```

## One notification per project, not one per ping

Every event from a project uses the group key `claude-code/<project>`, so Honk keeps them in one group. That decides how often your phone buzzes:

- The first ping pushes right away.
- Pings after it don’t each push. You get at most one update every 5 minutes, with the running count, and on your iPhone each update replaces the previous banner instead of adding one.
- A level louder than anything the group has pushed so far gets through right away, even within those 5 minutes: a permission request (Loud honk) after a finished response (Light honk), for example.

Both numbers are in the project’s **Settings**. **While a problem repeats, notify at most once every …** changes the 5 minutes. After a day without pings, the next one counts as new and pushes right away; **Group messages that arrive less than … apart** shortens that day, so each new work session starts with a push.

## Quieter: only when you’ve walked away

The `Stop` hook runs after every response, even while you’re watching the terminal. To get a push only when you’ve stepped away, delete the `Stop` block and change the matcher to `"permission_prompt|idle_prompt"`. Claude Code sends `idle_prompt` when it finished about 60 seconds ago and you haven’t typed since, so a push means it’s really waiting for you.

## What the push shows

The notification shows the title and the message, and the message can be the start of Claude’s reply, code included. For private work, open the project’s **Settings** and set **What notifications show** to **Generic (no content)**: the push then shows only the project name, and the text stays in the inbox. Or leave the reply out of the script altogether.

## Codex

OpenAI’s Codex CLI has a simpler hook: `notify` runs a program after each finished turn and passes the event as one JSON argument. This script sends the same Light honk, in a group of its own:

```bash
#!/usr/bin/env bash
# Codex runs this after each finished turn, with the event as one JSON argument.
set -a; . "$HOME/.config/honk/env"; set +a
project=$(basename "$(jq -r '.cwd // "codex"' <<<"$1")")
text=$(jq -r '."last-assistant-message" // empty | .[:280]' <<<"$1")

honk light "Codex finished in $project" "${text:-Done.}" \
  --group-key "codex/$project" --source "$(hostname -s)" --quiet || true
```

Save it as `~/.codex/honk.sh`, make it executable, and add one line to `~/.codex/config.toml`, with your own home folder in the path:

```toml
# a top-level key: put it above the first [section]
notify = ["/Users/you/.codex/honk.sh"]
```

Codex currently sends only finished turns (`agent-turn-complete`) to `notify`, so this covers the end of a task, not approval requests.
