Feature: PostAssistantMessage hook with display-modification capability (inline image rendering / OSC 1337 / Sixel passthrough)
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 
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:
- Claude Code takes the terminal as a TUI (alternate screen buffer, cursor control, live streaming).
- The alias-around-the-binary pattern breaks the TUI.
- 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
Stophook can emit asystemMessagetoast 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:
- A
--render-filter <cmd>flag toclaude(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. - 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
- The chip system: https://github.com/Peregrine-Technology-Systems/peregrine-group-marketing (private — happy to share details with maintainers on request)
- Our filter for the headless case:
scripts/iterm-render-chips.shin that repo - The honest coverage map documenting the gap:
brand-book/signal-flag-system.md§Rendering inline in iTerm2
Happy to share more context if useful.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗