Spent a chunk of time chasing a ghost in Claude Code’s hook system. The PostToolUse hook — fires after each tool invocation, perfect spot to nudge developers about pending devlog entries. Diagnostic confirmed everything works: hook fires, receives correct JSON on stdin, grep pattern matches. But echo output? Goes absolutely nowhere visible. Claude Code just swallows stdout from that hook silently.
The hook runs. It does its job. Nobody hears it scream.
Rather than building some Rube Goldberg workaround to surface output from a hook that doesn’t want to talk, I ripped PostToolUse out entirely. The Stop hook already covers this case — it fires at session end, runs timbers pending, and that output actually displays. One hook that works beats two where one is a phantom.
The removal itself touched a modest spread of files. Added a retiredEvents list so that on upgrade, the old hook config gets cleaned up automatically rather than leaving orphaned entries in people’s settings. Updated all the tests to match. Clean kill.
The nested session guard needed a small workaround too — CLAUDECODE= as an env var trick. Nothing glamorous, just the kind of thing that falls out when you’re testing hooks that spawn subprocesses. Shipped it all as v0.10.1.
Also fixed the landing page, which was still showing v0.9.0 like it was 2025. The version badge update was straightforward, but the terminal display had a fun little HTML problem: continuation line indentation was getting eaten by whitespace collapsing. Wrapped the leading spaces in <span> elements. The kind of fix that makes you briefly hate the web platform before remembering that white-space: pre exists in CSS but doesn’t play nice with the rest of the layout. Sometimes a span is just a span.
This post was written with AI assistance.