Files
freno-dev/marketing/approved/agent-done-signal/copy.md
fixture 0137703341 marketing: FRE-199 CTO review fixes — B1 precedence order, B2 false git-push example dropped, N1 hooks-guide attribution
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.
2026-11-05 21:42:26 +00:00

93 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 — the `osascript`
> example 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:
- **`Stop`** fires when the agent finishes responding — the end of a turn.
- **`Notification`** fires when Claude Code sends a notification. A permission
prompt is one of these: the hook's payload carries a `notification_type` of
`permission_prompt` and a message like "Claude needs your permission".
- **`StopFailure`** fires instead of `Stop` when 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
1. **Wire turn-end to a notification you will actually notice.** A `Stop` hook
that calls `osascript -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.
2. **Route permission waits separately from completions.** The `Notification`
hook'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.
3. **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.
4. **Surface the failure path too.** A turn that ends on an API error fires
`StopFailure`, not `Stop` — 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.