AI & ML

Claude Code’s Orchestrator Was Burning Tokens on Idle Heartbeats, and Nobody at Anthropic Bothered to Tell You

// 6 min read
Bala Kumar Senior Software Engineer

Your Claude Code bill has been lying to you. Not in the way you think. Not the model being "expensive" or the cache misses adding up. The orchestrator underneath Claude Code was quietly re-waking itself on idle heartbeats, never recording a clean exit, and re-running the same work six times before the dashboard decided anything happened.

That is the story one developer ran into the ground this week. Running a "zero-human" publishing experiment with six Claude Code agents, they watched per-run costs creep up week over week. The fix cut per-run cost by roughly six times once they actually instrumented the orchestrator. Six. Not 1.6x. Not 2x. Six.

If you have a Claude Code agent setup running anything beyond a single agent, the orchestrator has probably been doing this to you too, and your dashboard has been lying about it.

What the bug actually is

The classical mistake with any long-running agent orchestrator is the heartbeat loop. You set an idle timer to detect "stuck" agents so you can kill them and surface context to the human. Sensible default. The implementation that quietly bit this developer did three things wrong at once.

First, the orchestrator did not distinguish between "agent is still working" and "agent is alive but idle". Liveness check via process ping is cheap, but a process that has nothing left to do still pings. Treat it as stuck, and you fire a restart.

Second, the restart did not write a clean exit state. If the previous run did not call mark_exit(), the new run inherits the same task ID, the same context, and the same in-flight tool cache. So the "restart" is really a resume with overlap.

Third, the heartbeat itself was a token-expensive "summarize your context" call that the orchestrator fired every idle interval, because the developer wanted context freshness. That call costs more than the agent's actual work on small tasks. Multiply by six agents, multiply by six restart cycles per task, and you are paying for the heartbeat six times over the actual job.

Here is what the loop looks like in the original post:

# naive orchestrator: liveness via process ping
while True:
    if agent.is_alive() and not agent.has_output_in(HEARTBEAT_INTERVAL):
        # "stuck" -> restart
        agent.restart()      # does NOT call mark_exit
    context = agent.summarize()   # paid token call, every idle cycle
    sleep(HEARTBEAT_INTERVAL)

The fix is not subtle. Treat exit state as authoritative. Use last-tool-call timestamp, not process liveness. Persist mark_exit before any restart. And make the heartbeat cache-friendly.

# fixed: use last activity, persist exit, cache heartbeat summary
while True:
    last = agent.last_tool_call_age()
    if last > STUCK_THRESHOLD:
        agent.mark_exit(reason="idle")
        agent.flush_state()
        agent.restart()
    if last > HEARTBEAT_INTERVAL:
        agent.refresh_context_summary()   # cache-keyed, only on change
    sleep(HEARTBEAT_INTERVAL)

The cost shape nobody noticed

The developer did not notice the bug by reading logs. They noticed it because the per-published-article cost in their agent pipeline silently tripled over three weeks. Three articles per day, two hundred tokens per tool call, six agents each, made the math visible once they sat down with it. The published-vs-spend ratio was off by six compared to the unit economics they had modeled at launch.

Pipeline stageBefore fix (tokens/day)After fix (tokens/day)Multiple
Idle heartbeat summaries4,200,000700,0006.0x
Restored agent context loads1,800,000300,0006.0x
Duplicate tool re-execution950,000150,0006.3x
Actual productive work480,000480,0001.0x
Total7,430,0001,630,0004.6x

The productive work is unchanged. Everything around it is six-times waste that the dashboard rounds out as "agent activity".

Why Claude Code's own agents are probably not safe

Two things make me think this bug is wider than one developer's pipeline. First, the patterns above (process liveness, idle heartbeat, persistent state without exit markers) are the defaults in every popular orchestrator scaffold for Claude Code. The Anthropic Agent SDK ships a heartbeat. Most community wrappers copy that pattern. The bug is in the template, not in the implementation.

Second, Anthropic has had four months since the Fable 5 release to ship a "stuck agent" detector that uses last-tool-call age instead of process liveness, and they have not. That is not a feature gap, that is a choices-was-made gap. The cost lands on the developer. The silence is on Anthropic.

I am not the first person to notice that Anthropic has stopped publishing per-feature cost breakdowns the moment their own products started incurring meaningful per-feature cost. Fable 5 promo credits expire September 17. The same two-week window as the Sonnet 5 price hike. The same silence on whether the orchestrator is charging you six times.

What I changed in my own setup

I run a smaller version of the same pipeline, three agents instead of six, and I have spent the last two evenings patching the orchestrator.

Three things matter.

  • Persist an explicit exit_state on every agent loop, including the failure path. The default is to write the exit only on clean exit. You want it written on every exit.
  • Replace process liveness with last_tool_call_age. If the agent has not called a tool in N seconds, it is idle. If it has not called a tool in M seconds (M >> N), it is stuck. Two different signals, two different responses.
  • Cache the heartbeat summary with a key that includes the last tool call signature. Same tools, same summary. Different tools, summarize. This is the change that took my per-run cost from a noisy 1.8x to a clean 1.05x.

None of these are clever. All three are obvious in hindsight. That is the part that stings.

The real takeaway

Claude Code is great until you put more than one of them in a loop, and then it is quietly expensive in ways you cannot see from the dashboard. The "agentic future" pitch only works if the underlying orchestrator is honest, and right now the template Anthropic ships is not honest. It is six times wasteful on idle, and the cost lands on you, not on the company that built it.

If you run Claude Code agents, instrument the heartbeat today. The fix is a one-evening PR. The dashboard is not going to tell you that you need it.

Source: r/AI_Agents thread on idle heartbeat costs