Skip to main content
Back to Blog
Blog

Claude Code's Completion Signals Keep Changing. Here's How We Keep Up

Why keyword-matching on Claude Code's completion banner kept breaking, and what MadoHub actually trusts to know when an agent's turn is over.

MadoHub needs to know the instant an agent finishes a turn — that's the edge that fires routing, flips a tile from working to done, and tells a connected agent it's safe to pick up the output. For a while, our answer to "how do we know Claude Code is done" was a literal string match. It worked, until Claude Code shipped a release with a different word in it, and it stopped working. This is the story of what replaced it, and why the replacement isn't even the real fix.

The problem or insight

The word list that expired on schedule

Claude Code prints a one-line banner when it finishes a turn: something like ✽ Worked for 2m 30s. The very first version of our detector matched two specific verbs from that banner — Sautéed and Cogitated — because those were the words Claude Code happened to be printing at the time. Detection was a keyword check: see the word, start the idle timer, fire the route.

That held up for exactly as long as Claude Code kept using those two words. It doesn't. The verb is drawn from a rotating, whimsical set — Worked, Churned, Sautéed, Cogitated, and others — that changes across releases, seemingly as a bit of CLI personality. Every time the word list changed, our keyword match silently stopped firing, and every tile using it stopped detecting completions until someone noticed and added the new word.

Chasing a moving target by enumerating it is a losing game. The fix was to stop caring what the word is.

Match the shape, not the word

Every completion banner has the same structure regardless of which verb ships this week: a spinner glyph at the start of the line, a capitalized past-tense verb, the literal for, and a duration. Whatever verb ships next release, as long as it fits that shape, detection keeps working without a code change. The glyph requirement matters because terminal output is full of prose that fits "verb + for + duration" without meaning the turn is over — a retry loop printing Retried for 3s, a build step logging Waited for 5s. Require the glyph at the start of the line, and those false matches go away.

How MadoHub handles it

The banner match is acceleration, not the verdict

This banner match is not the primary way MadoHub decides a Claude Code agent is done — it's acceleration. The authoritative signal comes from a backend watcher that reads Claude Code's own session transcript directly: it looks at the last message written to the log, and if it's an assistant message with no pending tool call, the agent is done; if it's a user message, a progress message, or an assistant message mid-tool-call, the agent is still working. That verdict is labeled so the rest of the app can tell a transcript-backed fact apart from a screen-scrape guess.

The banner match exists only to shave latency off that watcher for the common case where you're staring at the terminal and want the tile to flip the moment the banner appears, rather than waiting for the watcher to catch up.

Why a missed match is fine, but a false one isn't

Given the choice between a match that's too strict and one that's too loose, MadoHub leans strict — a deliberate trade-off worth spelling out. A missed banner match is harmless: the watcher still reports the real stop shortly after. A false banner match is not harmless, because it can fire routing into a tile mid-turn. So MadoHub runs defense in depth on top of the screen match: if a screen-sourced "done" verdict shows up while a live watcher verdict says the agent is still working, MadoHub drops the screen verdict rather than acting on it — the watcher's word on completion is final.

Practical guidance

  • If you're watching a Claude Code tile and want to predict when a route will fire, don't memorize this week's verb. It'll be a different one in a few releases. Learn the shape instead: glyph, capitalized past-tense verb, for, duration, all on one line. That's the part of the signal Claude Code isn't going to stop printing, even as it keeps changing what word goes in the middle.
  • If a tile's state ever looks wrong, trust the watcher, not the screen. MadoHub does — the transcript is the signal it actually trusts, and the banner match is only there to make the common case feel snappier. If you see a tile flip to "done" and then flip back, that's the watcher correcting an over-eager banner match, not a bug.
  • Don't write your own routing that depends on a specific verb. If you're building Flows or connections that key off Claude Code completions, rely on MadoHub's state (working / done / failed) rather than matching banner text yourself — otherwise the next Claude Code release will silently break your setup the same way our first detector broke.
  • Expect a brief lag, not instant flips, when the watcher path is busy. The banner match makes the common case instant, but on a busy machine the watcher is the backstop that's always correct, and it may take a moment. A second or two of lag is normal; a tile that never flips is not.

This supersedes the shorthand version of this advice from our Claude Code tips post — that one told you to watch for the shape and move on; this one is the full explanation of why that shape is the right thing to watch, and why, underneath it, the session transcript is the signal MadoHub actually trusts.