The Notification That Lied to Me A developer built claude-code-notify, a Telegram notification tool for Claude Code sessions, after experiencing productivity losses from long TDD-driven tasks and parallel project management. The tool uses transcript-based matching on tool_use_id to accurately detect when background tasks complete, avoiding false positives from immediate acknowledgments. The developer also found that Claude Code's native SubagentStop hook is unreliable for background agents, making transcript parsing the only reliable signal. I was three projects deep. Project A had a review open in one VS Code window. Project B was running under Claude Code with the superpowers skill set, which means TDD: red, green, refactor, repeat — a mode that produces solid code but stretches a task from minutes into an hour or more. Somewhere in that hour, Claude hit a point where it needed my sign-off to keep going. I didn't notice. I was in Project A. By the time I switched back to Project B, it had been sitting there, blocked, for the better part of twenty minutes — doing nothing, waiting on me. That's the first problem: long, TDD-driven tasks create real decision points, and if you're not watching, you bleed time waiting for nobody. The second problem is the same failure wearing a different hat. I run multiple projects in parallel, each in its own VS Code window, each with its own Claude Code session. "Is anything done? Is anything stuck?" isn't a question I can answer without clicking through every window and every session, one at a time. Multiply that by a normal afternoon and it's a meaningful amount of dead time spent just checking. Both problems have the same shape: Claude Code knows when it's blocked or finished. I don't, because I'm not watching. So I built claude-code-notify — a tool that pings me on Telegram at exactly the moments that matter: when a turn is truly done, and when it needs me. The obvious fix is a Stop hook: Claude Code exposes one, you wire it to a script, the script fires a Telegram message. I did exactly that, first. It worked — until it didn't. The bug showed up as a notification that arrived too early. I'd get "finished," switch over, and find the terminal still working. The cause, once I found it, was almost embarrassing: Claude Code's Bash tool, when run with run in background=true , immediately returns an acknowledgment — something like "Command running in background with ID: …" — the instant the command is dispatched , not when it completes . A naive Stop hook that treats any matching tool result as "resolved" reads that ack as done. It isn't. The command is still running. Background Agent subagents have the same issue from a different angle: they don't emit an ack at all, so a hook that only tracks explicit "finished" signals just never sees them. So the naive hook was worse than useless for exactly the cases I cared about most — the long, multi-step, background-heavy turns that made me build this in the first place. The fix is a single rule: a background task — a subagent or a backgrounded Bash command — counts as resolved only when a