Blog · September 14, 2026 · 10 min read · by Vilva Athiban P B

Claude Code Notifications Not Working: A Diagnostic Checklist

You followed a setup guide. You set the config key. You ran a long task, went to make coffee, came back eleven minutes later and Claude Code had been sitting on a permission prompt for nine of them. No sound, no banner, nothing.

Claude Code notifications almost never fail for interesting reasons. There are four places the signal gets dropped, they are strictly ordered, and testing them out of order is why people spend an hour on a five-minute problem. Work down the list and stop at the first thing that is wrong.

The chain, in the order it breaks

A notification has to survive four hops: Claude Code decides to emit one, it picks a channel, your terminal turns that channel into something the OS understands, and the OS decides whether you are allowed to see it. Each hop fails silently, which is what makes this annoying to debug.

  1. Claude Code is using a channel your terminal cannot serve.
  2. Your terminal has the relevant feature switched off.
  3. The OS has not granted your terminal notification permission.
  4. The notification is firing correctly somewhere you are not looking.

Cause 1: the channel does not match your terminal

This is the big one, and it catches most people. Claude Code only sends a desktop notification natively in a handful of terminals — Ghostty, Kitty and iTerm2. If you are in macOS Terminal.app, VS Code integrated terminal, Windows Terminal, Warp, or basically anything else, the default channel has nothing to talk to and the notification evaporates.

The setting that controls this is preferredNotifChannel, a top-level key in ~/.claude/settings.json. The accepted values are auto, terminal_bell, iterm2, iterm2_with_bell, kitty, ghostty, and notifications_disabled.

The fastest diagnostic in this whole article: force the dumbest possible channel and see whether anything happens at all.

{
  "preferredNotifChannel": "terminal_bell"
}

Restart Claude Code and run something short. If you now get a bell, the emit side works fine and your problem was the channel. If you get nothing even from the bell, skip to cause 2 — the bell is a terminal feature and yours may have it muted.

Worth checking for a value you did not expect: if someone on your team shared a settings file, or you copied one from a blog post, you may have notifications_disabled sitting in there. It does exactly what it says and gives no indication that it is doing it. The full option breakdown is in our preferredNotifChannel guide.

Cause 2: the terminal is swallowing it

Terminals do not forward alerts by default, and iTerm2 in particular needs two separate things switched on before an escape-sequence alert becomes a Notification Center banner.

In iTerm2, open Settings, then Profiles, then Terminal. Enable Notification Center Alerts. Then, under Filter Alerts, enable Send escape sequence-generated alerts. People routinely find the first one already on and the second one off, which produces precisely the symptom you are debugging: the mechanism looks configured and nothing arrives.

If you set terminal_bell and heard nothing, the bell itself is probably muted. Most terminals have an audible-bell toggle buried in profile settings, and many people turned it off years ago after one too many tab-completion beeps. Turn it back on temporarily while you test, and consider iterm2_with_bell if you want both a banner and a sound.

Cause 3: the OS never granted permission

On macOS, open System Settings, then Notifications, and find your terminal app in the list. The permission has to belong to the terminal — Claude Code runs inside it and does not appear separately.

There is a useful piece of diagnostic information hiding here. If your terminal app is missing from the list entirely, it has never once attempted to post a notification. That is not a permissions problem at all; it means you are still stuck on cause 1 or 2, and fiddling with System Settings will not help. An app only appears in that list after its first attempt.

Also worth ruling out in about ten seconds: Focus modes and Do Not Disturb. A Focus that you set up for deep work and forgot about will suppress exactly the notifications you most wanted during deep work. If you use one routinely, add your terminal to its allowed list rather than turning the Focus off. If you are hitting the specific macOS message about Claude notifications being turned off, we covered that one separately in notifications are turned off for Claude.

Cause 4: it works, but not where you are

The last category is the one that feels like a bug and is not. The notification fired perfectly — into a machine, a session, or a screen that you were not in front of.

  • SSH. Claude Code running on a remote box emits its notification on that box. Escape-sequence channels can survive the hop to your local terminal; anything that calls a local OS API cannot.
  • tmux and screen. Multiplexers intercept escape sequences by design. Unless tmux is explicitly configured to pass the bell through, it stops there. Our tmux and SSH notifications guide covers the passthrough settings.
  • A background or hidden window. Some terminals suppress alerts from the frontmost tab on the theory that you can already see it. If you tested by watching the window, you may have tested the one case that is designed not to notify.
  • Detached and background tasks. Long-running background work does not always route through the same notification path as the main loop. Worth knowing if that is where your waiting happens.

A two-minute test that isolates the layer

Rather than changing three things and re-running a twenty-minute task, test the layers directly and from the bottom up:

  1. Run printf '\a' in your terminal. If you hear nothing, the bell is muted — that is a terminal setting, and no Claude Code config will fix it.
  2. Check whether your terminal appears in the OS notification list at all. Absent means nothing has ever tried.
  3. Set preferredNotifChannel to terminal_bell, restart Claude Code, and run a task that takes ten seconds. Bell means the emit side is healthy.
  4. Only then switch to your terminal-native channel and retest, with the terminal window in the background.

Four checks, each one eliminating a whole layer. The reason this beats guessing is that every layer fails the same way — silence — so the only way to tell them apart is to test them one at a time.

If you use hooks: why Stop and Notification hooks stay silent

Many people skip the built-in channel entirely and wire a Claude Code hook to afplay, osascript or terminal-notifier. Hooks have their own failure modes, and they are just as silent:

  1. The settings file is not valid JSON. One trailing comma in ~/.claude/settings.json and the whole file is ignored. Run python3 -m json.tool ~/.claude/settings.json — if it prints an error, that is your bug.
  2. The session started before you edited the hook. Claude Code reads its hook configuration when a session starts. Restart the session (or open /hooks to review the change) and confirm your hook is listed there.
  3. Wrong event name or nesting. The events are Stop (Claude finished responding) and Notification (Claude needs your input or permission), each holding a list of matchers with a nested hooks array. A hook placed one level too high never runs.
  4. The command fails quietly. Paste the exact command from the hook into your shell. A typo in a sound path such as /System/Library/Sounds/Glass.aiff, or a terminal-notifier binary that is not on the PATH Claude Code sees, fails without any output. Use absolute paths. Running claude --debug shows each hook as it executes.
  5. The banner belongs to Script Editor. Banners from osascript -e 'display notification …' are posted by Script Editor, so Script Editor needs notifications allowed in System Settings → Notifications. Clicking one of those banners also opens Script Editor, not your terminal.
  6. Focus is on. Do Not Disturb or any Focus mode hides banners from apps you have not allowed. The sound from afplay still plays, which is a useful tell: sound but no banner points at Focus or notification permission.

If you run Cursor, Codex or Gemini CLI too, each has its own hook format with the same failure modes, so expect to debug this once per tool.

When the terminal is the wrong place for this

Being honest about the ceiling here: every fix above puts the notification on the machine running Claude Code, in a terminal that has to be configured correctly, on an OS that has to cooperate. That chain works well when you are sitting at that machine with the window behind your browser. It works poorly when Claude Code is on a server, when you are in a meeting in another room, or when you have four sessions running and need to know which one is blocked.

If that is your situation, the terminal is not really the right destination for the signal — a phone notification removes the entire four-layer chain, because nothing about it depends on which terminal emulator you happen to like. If you would rather keep everything local, the notification hook scripts give you full control over what fires and when.

Either way, the goal is the same one: stop paying attention to a terminal that is not doing anything yet.

Keep reading

Desk Exercises for Programmers: 15 Moves to Do While Your AI Agent Codes

7 min read

Exercise While Coding: Turn Claude Code Wait Time Into Micro-Workouts

7 min read

Claude Code Notch Notifications on Mac: See When Claude Is Done Without Watching the Terminal

7 min read

Claude Code Tips and Tricks: 12 Ways to Use Claude Code Effectively

8 min read

Claude Code Multiple Sessions: How to Run Agents in Parallel Without Losing Track

6 min read

A Claude Code Workflow That Doesn't Involve Watching the Terminal

5 min read

Claude Code Hooks: A Practical Guide to Automating Your Agent Workflow

7 min read

Claude Code Auto Mode: Fewer Permission Prompts Without Living Dangerously

7 min read

Claude Code Subagents: How to Delegate Work to Specialized Agents

7 min read

Claude Code Context Management: Treat the Context Window Like a Budget

6 min read

Per-Subagent Model Selection: Route the Grunt Work Down, Keep the Judgment Up Top

7 min read

Skills and Plugins: How to Teach Claude Code Your Way of Working

7 min read

Claude Code Background Tasks: Run Long Commands Without Blocking Your Session

6 min read

Codex CLI Notifications: How to Get a Ding When Codex Is Done or Needs Input

7 min read

Cursor Notification When Done: Every Way to Get Notified When Cursor Finishes

6 min read

Claude Code Notifications: How to Get Notified When Claude Code Finishes or Needs Your Input

6 min read

Want to Be Notified When Claude Responds? How Claude Notifications Work on Web, Desktop, and Mobile

5 min read

Claude Code Notification Scripts: Copy-Paste Recipes for Every Platform

6 min read

Get a Ding the Moment Codex Needs Your Response

6 min read

Get Notified the Moment Claude Code Is Waiting for Your Input

6 min read

“Notifications Are Turned Off for Claude” — Here Is the Fix

6 min read

Codex Sound When Done: Make Codex CLI Play a Sound When It Finishes

6 min read

terminal-notifier + Claude Code: Native macOS Alerts When Your Agent Finishes

6 min read

Gemini CLI Notifications: How to Get a Sound or Alert When Gemini Finishes

6 min read

Get Claude Code Notifications on Your Phone

6 min read

Claude Code Remote Control, Explained

7 min read

preferredNotifChannel: Claude Code's Built-In Notification Setting

6 min read

Claude Code Notifications in tmux and Over SSH

7 min read

Claude Code Effort Levels: Why Your Setting Keeps Getting Ignored

8 min read

Codex vs Claude Code Notifications: How Each One Tells You It Is Done

8 min read

Claude Code Notifications Inside Your Editor's Terminal

7 min read

CLAUDE_CODE_DISABLE_BACKGROUND_TASKS Explained

7 min read

CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP Explained

8 min read

Cursor Alerts Explained: Every Alert Cursor Raises, and How to Control Them

7 min read

Claude Code Environment Variables: The Groups That Actually Matter

10 min read

Claude Code Notifications on WSL and Windows

9 min read

Claude Code Checkpoints and /rewind

8 min read

Claude Remote Control: How It Works, Turning It Off, and Auto Mode

7 min read

Claude Code /loop: Poll a Deploy, Babysit a PR, and Get Told When It's Done

8 min read

Setting Up NotchFit With OpenAI Codex CLI: Hooks, $notchfit-plan, and the Daily Flow

7 min read

Claude Mods Explained: What the New Plugin Layer Can Do, and How to Turn On 'You Should Know'

9 min read

NotchFit vs Mac Break Reminder Apps: A Clock or a Signal From Your Coding Agent?

8 min read

Claude Code Headless Mode: Running claude -p in Scripts and CI, and the Three Signals That It Finished

10 min read

Building a Movement Habit at a Desk: Use the Agent Run as the Cue, One Set as the Unit, and Streaks Carefully

8 min read

Claude Code MCP Servers Explained: Adding Servers, Choosing a Scope, Handling Secrets, and Why Long Tool Calls Go to the Background

10 min read

/notchfit:plan Explained: How Claude Code or Codex Writes a Weekly Workout Plan the Notch Can Actually Run

8 min read

Claude Code Spinner Verbs Explained: What “Pondering” and “Brewing” Mean, How to Change Them, and Why You Should Stop Watching the Spinner

7 min read

Why NotchFit's Done and Permission Alerts Wait Until Your Set Ends, When That Costs You, and How to Turn the Workout Off

7 min read

How to Resume a Claude Code Session: --continue vs --resume, Naming Sessions, the Session Picker, Branching, and What Comes Back

9 min read

NotchFit on a Mac Without a Notch: How Pill Mode Works on Mac mini, iMac, Mac Studio and a MacBook With the Lid Closed

6 min read

How to Run a Claude Code Session in the Background: /background, claude --bg, Agent View, and Getting Back to It

9 min read

What a Notch App Can See: NotchFit's Local-First Design, What the Claude Code and Codex Hooks Send, and What Stays on Your Mac

7 min read

Why Codex CLI Asks for Permission Every Time, and How to Tune the Sandbox and Approval Policy Without Going Full Access

8 min read

What to Do While Claude Code or Codex Works: A Simple Protocol for the Two-to-Twenty-Minute Gap in Every Agent Run

7 min read

Is It Possible to Get a Notification When Claude Code or Codex Hits a Reset? Yes for Claude Code: the quota_auto_resume Hooks, Explained

8 min read

What a MacBook Notch App Can Actually Do: The Five Kinds of Notch Utility, Their Trade-offs, and Where NotchFit Fits

7 min read

How to Make MCP Servers Not Take Up as Much Context in Claude Code: Tool Search, alwaysLoad, Scopes and Output Caps

8 min read

The notchfit Command Line: Drive Your Workout, Read Status as JSON, Validate Plans and Test the Notch Without Leaving the Terminal

7 min read