MessageDisplay Hook: Transforming Assistant Text at the Display Boundary¶
MessageDisplayfires on every outbound assistant message and lets a hook transform or hide the text before display.
What changed¶
Claude Code v2.1.152 (2026-05-27) added the MessageDisplay hook event. The changelog entry verbatim:
Added a
MessageDisplayhook event that lets hooks transform or hide assistant message text as it is displayed (Claude Code changelog).
The event sits on the outbound text path, between the model emitting a message and the harness rendering it to the terminal, IDE pane, or downstream consumer. Use this page when you want to act on what the user sees. To act on what the model sees from a tool call, use updatedToolOutput on PostToolUse instead.
The hooks reference documents the return shape: a hook sets hookSpecificOutput.displayContent to replace the on-screen text. The replacement is display-only — "the transcript and what Claude sees keep the original text" (hooks reference). The event has no matcher support and always fires on every assistant message that streams text.
Where it sits in the lifecycle¶
MessageDisplay is the symmetric primitive to PostToolUse output replacement — the same harness-owned rewrite boundary on a different channel. It is the missing fourth corner, outbound assistant text, that previously had no harness-side enforcement surface (Claude Code hooks reference):
| Hook | Channel | Reader |
|---|---|---|
UserPromptSubmit |
Inbound user text | Model |
PostToolUse (updatedToolOutput) |
Inbound tool output | Model |
MessageDisplay |
Outbound assistant text | User / downstream |
PreToolUse |
Outbound tool call | External system |
Practitioner use cases¶
Four use cases call for dedicated MessageDisplay handling rather than probabilistic prompt-side instruction:
- PII redaction at the screen: a regex or named-entity classifier strips emails, phone numbers, or internal hostnames before render. This is the last-mile guard for a screen-share viewer or shared transcript, distinct from upstream tool-output redaction (PII Tokenization in Agent Context).
- Citation insertion: a hook appends inline citations the model forgot, sourced from a per-session sources file, at the boundary rather than relying on recall.
- Banner injection: a hook prepends an "operating in autonomous mode" banner so a downstream operator UI cannot miss the context.
- Audit-trail capture: a side-effect hook returns the text unchanged and writes it to an append-only log. The action is capture, not transform.
Why it works¶
The harness, not the model, owns the display boundary: the model decides what to say, the harness decides what to show. Running redaction, citation insertion, and audit capture after generation guarantees the transformation runs regardless of what the model chose. This deterministic property makes hooks "ensure certain actions always happen rather than relying on the LLM to choose to run them" (Claude Code hooks guide). Prompt-side guidance shapes generation but cannot guarantee output shape, so the rewrite primitive belongs on the harness, not in CLAUDE.md or system prompts.
When this backfires¶
- Display and consumer divergence: the replacement is display-only. The transcript and what Claude sees keep the original text (hooks reference), so the utterance is never lost and verbose mode shows the original. The divergence that survives is between the transcript and any downstream consumer reading the rendered text, such as a screen-share viewer or a Slack relay. Unlike PostToolUse output replacement,
MessageDisplaycannot corrupt the canonical record. Log the rendered view separately only if a consumer needs it. - False sense of PII safety: display-side redaction does not stop the model reasoning over the secret, which already entered context, and does not close the leak path through later tool calls or chained sessions. For true safety, redact upstream through
PostToolUseoutput replacement, or by keeping the data out of context.MessageDisplayis the last-mile guard, not the primary control. - Hook latency on every assistant turn:
MessageDisplayfires on every assistant message, not per tool call, so a 200 ms hook adds 200 ms of perceived latency every turn. Heavy classifier or LLM-graded filters that are tolerable onPostToolUseslow the user down here. Keep the hot path to regex or string substitution, and defer slow classifiers upstream. - Undefined merge order across hooks:
MessageDisplayhas no matcher support, so every registered hook fires on every message. The hooks reference says matching hooks "run in parallel" but documents no merge order for competingdisplayContentvalues, so two rewriting hooks have no defined resolution. Register at most one rewriting hook, and reserve the rest for side-effect-only capture.
Key Takeaways¶
MessageDisplaywas added in Claude Code v2.1.152 (2026-05-27) and lets hooks transform or hide assistant message text before display (changelog).- It is the display-side analogue of
PostToolUseoutput replacement — same harness-boundary rewrite pattern, different channel. - Useful for PII redaction at the screen, citation insertion, banner injection, and audit capture — anywhere prompt-side instruction is probabilistic.
- A redaction hook here does not close upstream leak paths; the secret already entered context. Pair with
PostToolUseredaction for true safety. - Hooks fire on every assistant message, so latency is user-visible. Keep transforms cheap; defer classifiers to upstream events.
- The rewrite is display-only: the transcript and what Claude sees keep the original text (hooks reference), so it cannot corrupt the canonical record.