<!-- Generated from the same content as https://heard.dev/guides/hear-what-claude-code-is-doing. -->

# Make Claude Code Read Its Progress Out Loud on a Mac (2026)

Source: https://heard.dev/guides/hear-what-claude-code-is-doing

The Claude Code CLI can’t speak. Heard speaks short updates on a Mac, or you can pipe a MessageDisplay or TaskCompleted hook into say or use a narrator plugin.

Guide · Voice output for Claude Code · 9 min read

# How to make Claude Code read its progress out loud on your Mac.

Claude Code takes voice input with /voice, but the CLI does not speak to you. This guide covers which hooks fire during a run and which fire at the end, two small hooks that speak progress through macOS say, plugins that do it for you, and where Heard fits.

Hooks reference checked October 2026 · Heard and free options compared

Updated October 22, 2026

The short answer

## Use Heard for short spoken updates, or speak progress from a hook that fires mid-run.

Heard (heard.dev), the voice context layer for agents, makes Claude Code talk to you on macOS 14 or later: its app installs the Claude Code hook, so you hear a short line, not the raw text, when Claude asks a question, needs approval, fails or finishes. It does not read out each tool step. Without Heard, the Claude Code CLI takes voice input but does not speak to you. [`/voice`](https://code.claude.com/docs/en/voice-dictation) is dictation: it turns your speech into a prompt and reads nothing back. To have Claude Code talk to you instead of you watching the terminal, add a [hook](https://code.claude.com/docs/en/hooks) that fires during the run and pipe its text into the macOS `say` command: `MessageDisplay` runs as each message streams to the screen, `PostToolUse` after each tool call succeeds, and `TaskCompleted` when a task on Claude’s task list is done. The claude-code-narrator plugin sets this up for you and speaks tool steps as they happen; Aloud speaks questions, approvals, failures and a short gist of each finished reply, and keeps routine tool calls silent. Both are free (MIT) and speak with a local Kokoro voice.

To have Claude Code read its final reply out loud, or just say “it’s done” at the end of a turn, use a `Stop` hook: pipe its `last_assistant_message` field into `say` (config below), or see the [sound-when-done guide](https://heard.dev/guides/claude-code-sound-when-done) for chimes. If you use the Claude desktop app, some users report a play button that appears when you hover over a response in the Code tab and reads it aloud on demand; not everyone sees it yet ([#58429](https://github.com/anthropics/claude-code/issues/58429)).

(1) Progress vs. done

## Which hook fires when.

Claude Code runs hooks on lifecycle events. The usual read-aloud recipe uses `Stop`, which only fires once Claude has finished responding, so you hear nothing during a long run. These are the events in the hooks reference that are most useful for speech while Claude works, plus the two that tell you it needs you or has stopped.

-   `MessageDisplay`: while Claude’s message text streams to the screen, in batches of whole lines. The input carries `message_id`, `index` (the batch number, from 0), `final` (true on the last batch) and `delta` (the new lines). It has no matcher, and replies that are only tool calls do not trigger it.
-   `PostToolUse`: after each tool call succeeds. The matcher filters on tool name, such as `Bash` or `Edit|Write`, and the input includes `tool_name` and `tool_input`. Speaking every call gets noisy fast.
-   `TaskCompleted`: when a task on Claude’s task list is marked completed. The input includes `task_subject`, the task’s title. It only fires in sessions that have the task tools (see Option 2).
-   `Notification`: when Claude needs you, for example a permission prompt you have not answered for about six seconds ([set one up](https://heard.dev/guides/claude-code-needs-input-notification)).
-   `Stop`: when Claude finishes responding. Use it for “done”; the [sound-when-done guide](https://heard.dev/guides/claude-code-sound-when-done) covers chimes and speech.

(2) Read replies aloud

## How do I make Claude Code read its responses out loud?

Add a `Stop` hook that pipes Claude’s final reply into the macOS `say` command. Every Stop hook receives a JSON payload on stdin, and its `last_assistant_message` field holds the text of Claude’s final response. The [hooks reference](https://code.claude.com/docs/en/hooks#stop-input) recommends that field for read-aloud hooks rather than the transcript file, which may not include the last message yet when the hook fires (checked October 22, 2026). `Stop` fires once Claude has finished responding, so you hear the result of each turn; for updates during the run, use Option 1 below.

Where plain `say` wins: it is built into macOS, free, needs no account or app, and reads Claude’s own words exactly. Cap the length with `head -c`, because a final reply can be a long report and `say` reads every word, file paths and code included. If you would rather hear a sentence or two than the reply word for word, Heard (heard.dev), the voice context layer for agents, summarizes what Claude did instead of reading the raw text, and keeps several Claude Code or Codex sessions in one voice.

~/.claude/settings.json · read each final reply aloud (macOS)

```
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "async": true,
            "command": "jq -r '.last_assistant_message // empty' | head -c 300 | say"
          }
        ]
      }
    ]
  }
}
```

**Check it loaded**

Merge the `Stop` key into your existing `hooks` object, install `jq` with `brew install jq` if it is missing, then run `/hooks` in Claude Code and confirm the hook is listed under Stop. On Linux, use the `spd-say` version in the [sound-when-done guide](https://heard.dev/guides/claude-code-sound-when-done).

(3) Speak as it works

## A MessageDisplay hook that reads the start of each message.

This hook speaks the first batch of every message Claude writes, capped at 200 characters, so you hear how each update starts while the run continues. It reads the batch with `index` 0 rather than the one marked `final`: in interactive sessions the final batch only carries the last lines of the message, and the reference says it is empty when the message ends on a newline.

Keep `"async": true`. Per the hooks reference, Claude Code holds each batch of text on screen until a MessageDisplay hook returns, and `async` runs a command hook in the background so speech never delays the display. The config follows the hooks reference as checked in October 2026; run `/hooks` afterwards and confirm it is listed under MessageDisplay. If it is not, update Claude Code.

-   Every message starts its own `say`, so two messages close together can talk over each other.
-   `say` reads text literally. The command strips `*` and `#`, but file paths and code still come through as written.
-   In `claude -p` runs the hook fires once per message with the whole text at `index` 0, so the 200-character cap matters more there.

~/.claude/settings.json · speak each message as it starts

```
{
  "hooks": {
    "MessageDisplay": [
      {
        "hooks": [
          {
            "type": "command",
            "async": true,
            "command": "jq -r 'select(.index == 0) | .delta | gsub(\"[*#]\"; \"\")' | head -c 200 | say"
          }
        ]
      }
    ]
  }
}
```

**Already have settings?**

Merge the `MessageDisplay` key into your existing `hooks` object. Install `jq` with `brew install jq` if it is missing, and add `-v Samantha` (or any name from `say -v '?'`) after `say` to change the voice.

(4) Speak finished tasks

## A TaskCompleted hook for a quieter signal.

If hearing every message is too much, speak only when Claude ticks off a task on its task list. On a multi-step job that gives you one short line per finished step, such as “Done: Implement user authentication”.

Check one thing first. The tools reference says the task tools are on by default only on some models; on others Claude keeps no task list, so this hook never fires. Start Claude Code with `CLAUDE_CODE_ENABLE_TODO_TOOLS=1 claude` to turn them on. TaskCompleted also fires when an agent team teammate finishes its turn with tasks still in progress.

~/.claude/settings.json · speak each finished task

```
{
  "hooks": {
    "TaskCompleted": [
      {
        "hooks": [
          {
            "type": "command",
            "async": true,
            "command": "jq -r '\"Done: \" + .task_subject' | say"
          }
        ]
      }
    ]
  }
}
```

**Exit code 2 blocks the task**

A synchronous TaskCompleted hook that exits with code 2 stops the task from being marked completed. This one only speaks, and `"async": true` keeps it out of the way.

(5) Built in

## Desktop app, voice mode and screen readers.

Claude has a few speech features of its own. None of them speaks Claude Code CLI progress on its own. Screen reader mode comes closest if you already use VoiceOver.

-   Claude desktop app: some users report a play button that appears when you hover over a response in the Code tab and reads it aloud when you click it; not everyone sees it yet ([#58429](https://github.com/anthropics/claude-code/issues/58429)). It is on demand, not automatic.
-   Voice mode: Anthropic’s [help center](https://support.claude.com/en/articles/11101966-use-voice-mode) says that in Claude Cowork and Claude Code, dictation is available but voice mode is not. Voice mode is for chats on mobile, desktop and the web.
-   Screen reader mode: `claude --ax-screen-reader` prints labeled lines such as `claude:` and `tool:` that VoiceOver reads in order, and rings the terminal bell when Claude finishes a reply, when a prompt needs your answer, and when a tool that ran longer than 5 seconds finishes ([accessibility docs](https://code.claude.com/docs/en/accessibility)).

(6) Plugins

## Tools that narrate for you.

If you would rather not write hooks, these open-source projects install them for you. Each is free under MIT and speaks with a local voice by default. Where they beat Heard is platform: claude-code-narrator also supports Linux (its author has not yet verified Linux audio), and claude-read-aloud runs on Linux and Windows and adds a speaker button inside Claude Code’s VS Code chat box, while Heard runs on macOS only. The [text-to-speech comparison](https://heard.dev/compare/claude-code-text-to-speech) puts them side by side.

-   [claude-code-narrator](https://github.com/shreyas-s-rao/claude-code-narrator): a Claude Code plugin that speaks a short line for each tool step, the text between tool calls, the opening of the final reply and notifications, with a local Kokoro voice on macOS or Linux. The closest match to “read its progress out loud”.
-   [Aloud](https://github.com/softcane/aloud): local Kokoro speech on macOS for Claude Code and Codex. It speaks questions, approval requests, blockers and a short gist of each completed reply, and keeps routine tool calls silent.
-   [claude-read-aloud](https://github.com/MichaelPGifford/claude-read-aloud): a plugin plus a VS Code extension that puts a speaker button in Claude Code’s chat box. It reads replies on demand or automatically, with system voices or a local Kokoro voice. The in-chat button is opt-in because it patches the installed Claude Code extension.

(7) A voice layer

## Heard: summaries instead of a readout.

The hooks above read Claude’s own words, and the plugins mostly do too: claude-code-narrator speaks a short line per tool step, and Aloud trims each reply to a short gist. Heard decides what is worth saying across all your sessions: it speaks questions, approvals, blockers, failures and final results in a sentence or two, and leaves out tool-by-tool progress. With several Claude Code or Codex sessions running, it keeps each session’s context separate, names the project in each update and keeps routine tool steps quiet. On Heard Power you can answer back by voice.

The engine is [open source](https://github.com/heardlabs/heard) under Apache 2.0 and speaks with a local Kokoro voice. The Mac app is the managed build, needs macOS 14 or later, and installs its Claude Code hook for you. Every new account starts with 14 days of free Heard, no card required; see [pricing](https://heard.dev/pricing) for the plans.

-   Summaries, not a transcript read aloud.
-   Several sessions, one voice.
-   Answer back on Power.
-   macOS 14 or later; open-source engine available.

Open source engine, from source

```
git clone https://github.com/heardlabs/heard
cd heard
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
heard install claude-code
```

**Prefer the app?**

The managed Mac app installs and manages the Claude Code hook for you. Turn it on in Heard and start Claude Code as usual.

Quick start

## Hear your first Claude Code session with Heard

1.  01
    
    ### Install
    
    Download Heard on a Mac running macOS 14 or later and sign in, or build the open-source engine.
    
2.  02
    
    ### Enable Claude Code
    
    Turn on the integration; Heard installs and manages the Claude Code hook.
    
3.  03
    
    ### Run a task
    
    Start Claude Code as usual on a task with a few steps and listen for the spoken updates.
    
4.  04
    
    ### Hear the first update
    
    Run a short task and listen: questions, approvals, failures and finished work are spoken. Mute updates when you need quiet.
    

A few more details

## Questions?

### Can Claude Code talk to me instead of me watching the terminal?

Not by itself. The CLI has no spoken output and `/voice` is dictation only. Add a hook that pipes Claude’s text into `say`, install a plugin such as claude-code-narrator or Aloud, or use Heard, which speaks short summaries of each session.

### Can it read progress while it works, not just at the end?

Yes, with a hook that fires mid-run. `MessageDisplay` runs as each message streams to the screen, `PostToolUse` after each tool call succeeds, and `TaskCompleted` when a task is ticked off. `Stop` only fires when Claude has finished responding.

### Why does the MessageDisplay hook read the first batch instead of the final one?

In interactive sessions each batch carries only the lines that are new since the last one, and the hooks reference says the final batch is empty when a message ends on a newline. The first batch always holds the opening of the message.

### Will a speech hook slow Claude Code down?

Not if you set `"async": true`, which runs the command in the background. Without it, Claude Code waits for the hook, and for MessageDisplay that means holding text on screen until `say` returns.

### Does Claude’s voice mode work in Claude Code?

No. Anthropic’s help center says Claude Code and Claude Cowork have dictation but not voice mode. In the desktop app’s Code tab, some users report a play button that reads a response on demand.

### Does spoken progress work with several sessions at once?

Plain `say` hooks in several sessions can talk over each other. claude-code-narrator queues speech from all sessions through one player, and Heard keeps per-session context, names the project in each update and keeps routine tool steps quiet.

Keep going

## Related Heard resources

[**Text-to-speech for Claude Code** say hook, narrator plugins, VoiceMode and Heard compared.](https://heard.dev/compare/claude-code-text-to-speech) [**Play a sound when Claude Code finishes** Copy-paste Stop and Notification hooks for every OS.](https://heard.dev/guides/claude-code-sound-when-done) [**Get notified when Claude Code needs you** Notification hooks for approvals, questions and idle prompts.](https://heard.dev/guides/claude-code-needs-input-notification) [**Claude Code integration** How the native Heard adapter connects.](https://heard.dev/integrations/claude-code)

## Give your agents a voice.

Keep the context. Get on with your work.

[Download for Mac](https://heard.dev/download/use-cases?format=dmg)

Includes 14 days of free Heard. No card needed.
