[FEATURE] Let a hook suppress or relabel its command in the completion display
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet — related but distinct: #64119 covers a hook's stdout + a
suppressOutputregression, and #67193 coversadditionalContextfeedback. Neither suppresses or relabels the hook's command display addressed here. - [x] This is a single feature request (not multiple features)
Problem Statement
When a command hook completes, Claude Code renders the hook's full command string verbatim as a "Shell command" block in the transcript. For example, after a context compaction the PreCompact hook shows:
Compacted PreCompact [sh "${CLAUDE_PROJECT_DIR}/.../hook-runner.sh" "${CLAUDE_PROJECT_DIR}/.../python" ${CLAUDE_PROJECT_DIR}/.../consolidate.py pre-compact] completed successfully
For people who don't read code, a block of shell appearing in a status line reads like an error — even though the hook succeeded and did exactly what it was supposed to. It's most visible right after every compaction (the PreCompact hook) and at session start.
suppressOutput: true governs a hook's stdout (#64119), and #67193 covers additionalContext feedback — but neither hides or changes the rendered command itself. There is currently no way to keep a legitimate, successful hook from surfacing raw shell to the user on completion.
(Surface: Claude desktop app 1.13576.0, macOS. This is a normal, successful command hook — not an error, and not about stdout.)
Proposed Solution
A way for a hook registration (or its JSON response) to control how — or whether — its command is shown on completion. Any one of these would solve it:
- A per-hook setting in
.claude/settings.json, e.g."display": "silent"(show nothing on success) or"label": "Consolidating memory…"(show a human-readable label in place of the command string); or - Extend
suppressOutput: trueso it also suppresses the command/completion card on the success path, not just stdout; or - Honor
statusMessage(or an equivalent) for the completion line, so a hook can present a plain-language description instead of its raw command.
The default (show the command) is fine — this is about letting a hook author opt into a quieter or human-readable presentation for routine, successful hooks.
Alternative Solutions
- We collapsed our hooks' inlined shell into a single small launcher script so the displayed command is one line instead of a multi-line
while … sleep … exec …block. It helps, but the line is still raw shell (sh "…/hook-runner.sh" …) and still reads as code to a non-coder — shortening the command can't make it read as a benign status. - Removing the hook isn't an option (it does real work, or is reserved for it), and
disableAllHooksis far too broad.
Priority
Medium - Would be very helpful
Feature Category
Configuration and settings
Use Case Example
- A tool/framework wires Claude Code hooks (SessionStart, PreCompact, Stop, …) on behalf of non-engineer end users.
- A long session compacts; the
PreCompacthook fires and succeeds. - Today the user sees
Compacted PreCompact [sh "…" "…" …consolidate.py pre-compact] completed successfully— a line of shell that looks like something broke. - With this feature, the hook could present
Pre-compact: consolidating memory ✓(or simply nothing on success), so the user sees a benign, legible status instead of code.
Additional Context
- Related: #64119 (hook stdout +
suppressOutputregression) and #67193 (suppressadditionalContextin Stop hooks) — both adjacent; neither covers the command-display case here. - This matters most for tools that present Claude Code to non-technical end users, where any raw shell in the conversation undermines trust even when nothing is wrong.