Hook to post-process assistant output before TUI render (refile of #56428)
Refiling #56428, which was closed by the stale bot on 2026-06-30 with
"Please open a new issue if this is still relevant" rather than by a
maintainer decision. It is still relevant, and I now have a concrete
recurring case.
Request
A new hook event (e.g. AssistantMessage or PreRender) that receives
the assistant's final message text and can return a transformed string
before it renders to the user.
Use case
Deterministic enforcement of output-style rules without burning tokens
on Stop-hook retry loops:
- Hard-wrap prose at N chars (terminal width preference)
- Strip filler phrases
- Redact patterns (secrets, internal hostnames)
- Inject footers / signatures
- Convert markdown flavors
Why existing hooks don't cover it
Stopfires after the stream is rendered. It can only block and
force a retry — costly, non-deterministic, adds latency.
UserPromptSubmitruns pre-model and cannot see output.SessionStartinjection is instruction-only, so it is subject to the
same drift as CLAUDE.md.
- There is no
PostToolUseequivalent for the assistant message.
Scope: all assistant text output, not one formatting rule
To be explicit, since the example below is a width case: the request is
a general post-processing point for assistant text, not a line-wrap
feature. Width is simply the instance easiest to demonstrate. The same
hook covers length caps, structural rules (no tables, no headers, no
bulleted walls), house style, redaction, and format conversion — any
rule expressible as a text transform.
The unifying property is that none of these need model judgment. They
are the rules a user can state exactly, which is precisely the set that
should not depend on probabilistic adherence.
Concrete case since the original filing
I keep a stated preference for output hard-wrapped at ~75 chars, held
in both CLAUDE.md and persistent memory, and reinforced by a
SessionStart hook that injects a terseness block every session. In a
long working session today the model still drifted well past it, and I
had to interrupt the work to say I could not read the output.
Two things make this specifically a post-processing problem rather than
a prompting problem:
- Wide markdown tables cannot wrap at all. Once emitted they run
off the terminal regardless of any width instruction. A text
post-processor could reflow or convert them; the model can only be
asked to avoid them, which it does unreliably over long contexts.
- Drift scales with conversation length. Instruction adherence
decays exactly when a session has accumulated the most context —
which is when readable output matters most.
Neither is a judgment call. Line wrapping and table reflow are
deterministic text transforms, which is what makes a pure-text hook the
right layer.
To put it plainly: this is a tooling gap, not a prompting problem.
Instruction adherence is probabilistic by nature, so no amount of
strengthening the wording converts a formatting preference into a
guarantee. Every other class of rule in Claude Code that must hold
deterministically — permissions, tool gating, session end — has an
enforcement point. Output formatting is the one that does not, and it
is the class least in need of model judgment.
Shape suggestion
Input JSON on hook stdin:
{
"hook_event_name": "AssistantMessage",
"message": "...assistant text...",
"transcript_path": "/path/to/transcript.jsonl",
"session_id": "..."
}
Hook returns JSON on stdout:
{"replacement": "...new text..."}
Or exits 0 with empty stdout to pass through unchanged.
Precedent
Stop already gates session end. This would be the symmetric mutation
point one layer earlier, between model completion and TUI render.
Prior interest
#56428 drew a +1 from @liviuignat, who wanted the same hook for PII
redaction via Presidio — a case where instruction-only enforcement is
not merely unreliable but unacceptable.