Feature: PostAssistantMessage hook with display-modification capability (inline image rendering / OSC 1337 / Sixel passthrough)

Open 💬 2 comments Opened Jun 2, 2026 by amalc

Summary

Add a hook event that fires when an assistant message finishes rendering in the interactive REPL, and whose stdout can be written to the terminal after (or as part of) the assistant's last line. This would enable use cases that currently work only in claude --print (headless) mode — most concretely, inline image rendering via iTerm2 OSC 1337, Sixel, or the Kitty graphics protocol.

Concrete use case

We have a per-seat signal-flag chip iconography system across our org (~67 repos). Every Claude-authored sign-off in a GitHub issue/PR comment includes a markdown image:

— Claude Opus 4.7 · group-marketing ![GRP](https://.../peregrine-group-marketing.png)

GitHub renders the markdown image correctly. In a local iTerm2 session, the markdown shows as literal text. We built a tiny shell filter that detects the chip URL and substitutes an iTerm2 OSC 1337 inline-image escape sequence, so the chip renders as the actual PNG in-flow at the end of the line.

The filter works perfectly for claude --print (one-shot / pipe mode). It cannot reach the interactive REPL because:

  1. Claude Code takes the terminal as a TUI (alternate screen buffer, cursor control, live streaming).
  2. The alias-around-the-binary pattern breaks the TUI.
  3. No existing hook can rewrite, append to, or inject into the rendered assistant message. I verified this against the hooks reference — the Stop hook fires after the response completes but its stdout doesn't reach the terminal display.

Proposed shape

A new hook event, tentatively PostAssistantMessage (or AssistantMessageRendered), that:

  • Fires after the assistant's message has been rendered to the terminal.
  • Receives the rendered message text via stdin (or a JSON envelope on stdin).
  • Has its stdout written to the controlling TTY after the assistant message — i.e., a new line below the rendered message, OR (richer option) replaces the assistant message with the hook's stdout if a flag is set.

Minimal-surface variant: even just \"hook stdout is written to TTY on a new line after the assistant message\" would unlock inline-image rendering (the OSC escape lands on a line of its own, immediately below the sign-off — visually close enough).

Why this is worth the architectural ask

The interesting use cases here go beyond chip iconography:

  • Sixel / Kitty graphics protocol support for terminals that don't natively render images (most of them)
  • Diagram embedding (PlantUML, Mermaid) inline in REPL responses
  • Status decoration (CI badges, build-status icons, deploy chips)
  • Accessibility post-processing (high-contrast colorization, font-size hints for tmux/screen wrappers)
  • Logging / mirroring — write the assistant's message to a side channel without breaking the live display

All of these are blocked today by the same architectural gap: the hook system is a side-channel (JSON in, JSON out) with no display seam. A single \"hook with TTY-write privilege\" event closes the gap for many use cases.

What I've already verified

  • Hooks reference enumerates events: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PermissionRequest, Stop, StopFailure, SessionEnd. None can write to the display.
  • The Stop hook can emit a systemMessage toast and set internal state, but its stdout does not reach the rendered output stream.
  • Output Styles modify the system prompt / response shape, not the rendering pipeline.
  • Fullscreen rendering, Status Line, and Terminal Config don't expose a per-message post-render hook.

Acceptable alternatives

If a full PostAssistantMessage hook is too heavy, two smaller surfaces would also work:

  1. A --render-filter <cmd> flag to claude (interactive mode) — output passes through <cmd> before being written to the TTY. This is the moral equivalent of the alias-pipe pattern, made TUI-safe by Claude Code.
  2. OSC passthrough in markdown — when Claude emits an <img> tag or a special markdown extension referencing a local image path, Claude Code renders it via iTerm2 OSC 1337 / Sixel / Kitty protocol natively (terminal capability detected). No hook needed; the rendering happens at the source.

The second option is cleaner architecturally but has more product surface.

Background

Happy to share more context if useful.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗