B1 (agent-waiting-on-permission): body said 'allow / ask / deny' — inverted vs the permissions doc's deny → ask → allow. Fixed; fact-check row 3 was already correct and now matches the body. B2 (agent-run-without-asking): dropped the 'Bash(git commit *) allowed with Bash(git push *) denied is a policy the agent cannot talk its way around' example — the docs' own 'What a Bash rule doesn't match' table names Bash(git push *) as not stopping git -C . push origin main and friends. Sentence narrowed to the precedence claim, with a pointer to step 4's caveat. N1 (agent-done-signal): the osascript desktop-notification example is in the hooks guide (code.claude.com/docs/en/hooks-guide), not the hooks reference. Body and fact-check row 4 fixed. Pair-1 citations standardised from docs.anthropic.com to code.claude.com per the review's optional note. Each page's status blockquote records the revision.
5.9 KiB
How do you know when your coding agent is done?
Status: approved — sponsor fact-check passed 2026-11-05 (FRE-199 fact-check card, verdict: "Approve both — move to approved/"). Not published; a human places it on nook.freno.me from
approved/. This page never names a product of ours and never names a competitor. Internal target: first page of the FRE-199 pair, Thu 2026-11-06. CTO review 2026-11-05: changes requested and applied — theosascriptexample is attributed to the hooks guide, not the hooks reference; pair-1 citations standardised to code.claude.com.
Often, you don't — not from the terminal alone. A coding agent's turn can end in silence: the prompt returns, the cursor blinks, and a finished turn looks exactly like one that stalled, is still running, or is waiting on you. The fix is to stop trusting silence and wire the two moments that matter — the turn ended and the agent needs you — to something you will actually see.
Why silence is the failure mode
A terminal coding agent ends a turn by printing a prompt. If you are in another window, another room, or running several agents at once, nothing in that output distinguishes "finished" from "blocked on a permission prompt" from "dead". The task being done and you finding out are two different events, and the second one has no default signal.
Practitioners keep rediscovering this. One operator running a self-hosted queue of autonomous agent sessions described sessions that "finished their work but never sent the done signal, and held their slots for hours" — their fix was to derive "done" from git state plus an idle transcript instead of trusting the agent's own signal. A public service post about a code-review plugin described the mirror image: a green checkmark and "No findings" when the review had not run at all. An empty result and a successful result rendered identically.
That is the trap in one sentence: zero looks exactly like success.
What the turn-ending signal actually is
Claude Code gives you two hooks that bracket the moments worth surfacing:
Stopfires when the agent finishes responding — the end of a turn.Notificationfires when Claude Code sends a notification. A permission prompt is one of these: the hook's payload carries anotification_typeofpermission_promptand a message like "Claude needs your permission".StopFailurefires instead ofStopwhen the turn ends on an API error — rate limits, authentication problems, and the like.
All three can run a command of your choosing. The hooks reference documents the
events; the hooks guide includes a desktop-notification example built on
macOS's osascript.
What to check or do
- Wire turn-end to a notification you will actually notice. A
Stophook that callsosascript -e 'display notification …'(or your terminal's notification escape) turns the silent prompt-return into a visible event. A terminal bell is not this — it is mute the moment you switch windows. - Route permission waits separately from completions. The
Notificationhook's payload tells you which kind it is. A permission wait means the agent is blocked on you; treating it as "done" hides the one state that costs the most time. - Don't trust the exit signal alone. Check the artifacts:
git status,git log, whether the transcript has gone idle. The queue operator's rule generalises — a "done" that has to name what it is waiting on is a "done" you can act on. - Surface the failure path too. A turn that ends on an API error fires
StopFailure, notStop— an alert wired to the wrong one misses exactly the runs that need attention.
One next step: take the agent command you run most often and give its end-of-turn a notification you would notice from across the room. That single wire closes the most expensive silence in the workflow.
Fact-check table (not part of the page)
Every technical claim above, with its primary source. Claims about Claude Code's behaviour come from its own documentation, re-read 2026-11-05.
| # | Claim in the page | Source |
|---|---|---|
| 1 | Stop fires when the agent finishes responding (end of a turn); hook cadence is "per turn: UserPromptSubmit, Stop, StopFailure" |
Claude Code hooks reference — https://code.claude.com/docs/en/hooks |
| 2 | Notification fires "when Claude Code sends a notification"; example payload carries notification_type: "permission_prompt", message "Claude needs your permission" |
same hooks reference (Notification event section) |
| 3 | StopFailure "runs instead of Stop when the turn ends due to an API error" (rate limits, authentication) |
same hooks reference (StopFailure section) |
| 4 | Hooks run a command of your choosing; a desktop-notification example using osascript is in the hooks guide |
Claude Code hooks guide — https://code.claude.com/docs/en/hooks-guide (desktop-notification example) |
| 5 | Operator anecdote: sessions that finished work but never signalled done, holding slots for hours; fix = derive done from git + idle transcript | r/ClaudeCode thread 1xjb3j0 ("Are you running a self-hosted queue of autonomous Claude Code sessions?", 2026-10-31), quoted in drafts/listening.md Scan 4 addendum. Quoted as one operator's described practice, not a measurement. |
| 6 | PSA anecdote: code-review plugin showed green check + "No findings" without running | r/ClaudeCode 1xmnz2c (2026-11-03), logged in drafts/listening.md Scan 6. |
| 7 | "Zero looks exactly like success" | Verbatim buyer phrasing, three independent instances (1xm09fs, 1xmnz2c, plus HN repeats) in drafts/listening.md Scans 5–8. Used as the problem's name, attributed to no one. |
Ban compliance: no product of ours named · no competitor named · no superlatives · no benchmark numbers · no invented testimonials (anecdotes are real threads, described without handles) · no price · no roadmap dates.