The Heartbeat Bill

Always-on agents like Claude Duet, OpenAI Dots and Meta Muse wake on a schedule to read your mail, and most of what they cost is the check-ins, not the tasks. Teams are building the same pattern on the API. Past the cache TTL, an Opus 5.5 agent checking every 3 hours costs $35.52 per seat-month in our model, more than checking every hour ($25.92), because its 30K-token prefix bills at $4 per million instead of $0.20. A zero-token cursor diff, a Haiku 5.5 triage call on only the new items, and Opus only for real events cut that to $10.17, $304,200 a year at 1,000 seats. Includes heartbeat.py, 75 lines that gate the check-ins, fail open, audit 5% of sleeps, and price your own schedule.

Published 2026-11-01 by Dor Amir on the Nadir blog.

Filed under Agents.

TL;DR.

Claude Duet, OpenAI Dots, and Meta Muse launched within seven weeks of each other, and they're built the same way: an agent that wakes up on a schedule, reads your mail, calendar, and docs, and decides whether anything needs you. Teams are now building the same pattern on the API for their own staff and customers: inbox watchers, CRM watchers, on-call agents, deal-desk agents. In each of them, most of the cost goes to the check-ins, not the tasks.

Product facts are from Anthropic's and OpenAI's launch pages and launch coverage, retrieved November 1, 2026. Prices are Anthropic list prices on the same date. The seat model (30K-token prefix, 24K tokens of new items a day, 2 actionable events a day) is ours and illustrative. No figure here comes from Nadir customer data.

Three agents, seven weeks.

Meta MuseOpenAI DotsClaude Duet
LaunchedEarly September 2026September 29, 2026 (DevDay)October 21, 2026 (research preview)
ModelNot stated in launch coverageGPT-6 AstraBuilt around Claude Opus 5.5
Background modeOwn computer and browser, keeps working"Proactive research" with read-only toolsChecks connected accounts "every few hours"
How background work is billedFree with a usage limit, from $20 a month afterIncluded with Pro and up. More Dots or more volume "will cost extra later on""Its background checks count toward" your plan limits
Acts without asking?Asks before sensitive actionsCustom Rules: allow, require approval, or banAsks before sending, paying, signing, or deleting

Anthropic's launch page explains why Duet checks every few hours instead of every few minutes. It's to avoid using up plan limits too quickly. Background checks count against the same limits as your chats, and bigger tasks "require more model turns and background work."

That tells you most of what you need to know about the economics. Even the company that sells the model limits how often the agent is allowed to look. If you're building the same pattern on the API, nobody sets that limit for you. Your bill is check-ins per day times the cost of each check-in, times the number of seats.

What one check-in costs.

A background agent doesn't wake up empty. Before it reads a single new email it loads its system prompt, the user's memory, its skills, and the tool definitions for every connected app. We use 30,000 tokens for that prefix. Agents with many connectors carry more.

On a 3-hour schedule, one check-in on Opus 5.5 looks like this:

LineTokensRateCost
Prefix (system, memory, skills, tool schemas)30,000$4.00 / M, cache expired$0.120
New items since last check6,000$4.00 / M$0.024
Output (reasoning and verdict)800$20.00 / M$0.016
Check-in total$0.160

Most of that $0.160 goes to re-reading a prefix that didn't change. Opus 5.5 cache reads cost $0.20 per million, a twentieth of the input price, so a warm cache would take the prefix line from $0.120 to $0.006. The cache isn't warm, though. Anthropic's default TTL is 5 minutes and the extended one is 1 hour. A check-in every few hours always arrives after the cache has expired.

Caching it anyway makes things worse. A 1-hour cache write costs 2x input, and on a 3-hour schedule nothing reads it before it expires. We covered that trap in The Cache Write Tax. On a heartbeat slower than the TTL, every cache write is wasted.

Checking less often can cost more.

Grouped bar chart of monthly check-in cost per seat by check-in interval. Every 15 minutes: Opus 5.5 on every tick $73, skip empty ticks $42, diff plus Haiku triage $18. Every 30 minutes: $42, $26, $13. Every hour: $26, $18, $11. Every 3 hours: $36, $19, $10. Every 6 hours: $19, $11, $11.
Grouped bar chart of monthly check-in cost per seat by check-in interval. Every 15 minutes: Opus 5.5 on every tick $73, skip empty ticks $42, diff plus Haiku triage $18. Every 30 minutes: $42, $26, $13. Every hour: $26, $18, $11. Every 3 hours: $36, $19, $10. Every 6 hours: $19, $11, $11.

In the gray bars, a frontier agent runs on every tick. The dip and rise between 1 hour and 3 hours is the cache cliff. At one check-in an hour, a 1-hour cache stays warm and each tick pays $0.006 for the prefix. At one check-in every 3 hours, there are a third as many ticks, but each one pays 20x as much for the prefix, so the month costs 37% more.

In the orange bars, the agent goes through three gates first. That line is almost flat, between $10 and $18 at any interval. It barely moves because its cost now follows how many things happened, not how many times the agent looked. Two actionable events a day cost about the same whether you catch them within 15 minutes or within 3 hours.

That changes the product decision. Without gates, a faster schedule costs more, so the agent checks every few hours and is slower to notice what matters. With gates, the faster schedule costs about half of what the ungated 3-hour schedule costs.

Three gates.

Funnel for one seat on one day with check-ins every 3 hours. 8 ticks go through a cursor diff at $0.000 a day. 4 ticks with new items go to Haiku 5.5, which reads only the new items, at $0.003 a day. 2.1 wake the Opus 5.5 agent, 2 real events and 0.1 audits, at $0.336 a day.
Funnel for one seat on one day with check-ins every 3 hours. 8 ticks go through a cursor diff at $0.000 a day. 4 ticks with new items go to Haiku 5.5, which reads only the new items, at $0.003 a day. 2.1 wake the Opus 5.5 agent, 2 real events and 0.1 audits, at $0.336 a day.

Gate 0: ask the source what changed. Most APIs a background agent reads can tell you what changed since your last look, without returning everything. Gmail's users.history.list takes a startHistoryId. Google Calendar's events.list takes a syncToken and returns only changed events. GitHub honors If-None-Match, and a 304 Not Modified doesn't count against your primary rate limit. Slack, Linear, and most CRMs have a cursor or an updated_since filter. If nothing changed, the tick ends here and spends no tokens. In our model that's half of all ticks: nights, weekends, and quiet afternoons.

Gate 1: a small model reads only the new items. The triage call doesn't need the agent's memory, skills, or 40 tool schemas. It needs the new items and a short rubric (does anything here need a reply, a decision, or action within 24 hours?). On Haiku 5.5 that's 7,500 tokens in and 50 out, $0.0008 per call, about 200 times cheaper than an Opus check-in. In our model it handles 4 calls a day for $0.003.

Gate 2: the frontier agent wakes for events, not ticks. Only when triage says "wake" does the full agent load, with its prefix, memory, and tools, and do what Duet or Dots would do. That's 2 real events a day in our model, plus a few audit wakes (below).

Two cheap guards go in front of triage: an allowlist of senders, and keywords that always wake the agent without asking the small model. Your CEO, the on-call alias, and anything containing "outage" don't need a classifier.

What a missed wake costs.

The real risk with this design is a triage model that sleeps through something important. Anthropic's launch page says Duet itself "might misread a thread or miscalibrate what's urgent," and that's with Opus reading everything. A smaller model will misjudge more often. The design has to plan for that.

Gating isn't free. Each check-in adds one small-model call, and on a 3-hour schedule with 6,000 tokens of new items, Haiku adds well under a second. That's fine for a background agent, since nobody is watching it think.

1,000 seats, one year.

Horizontal bar chart of annual check-in cost for 1,000 seats on a 3-hour schedule. Opus 5.5 on every tick $426,240. Skip empty ticks $230,400. Diff plus Haiku triage $122,040.
Horizontal bar chart of annual check-in cost for 1,000 seats on a 3-hour schedule. Opus 5.5 on every tick $426,240. Skip empty ticks $230,400. Diff plus Haiku triage $122,040.

Rolling an always-on agent out to a 1,000-person company changes the scale. In our model, a frontier agent checking every 3 hours costs $426,240 a year in check-ins alone, before any of the work people actually asked it to do. Skipping empty ticks takes that to $230,400. Adding triage takes it to $122,040.

These numbers depend on our assumptions. Change the prefix size, the volume of new items, or the event rate, and they move. What doesn't change is the structure: an ungated agent pays for the clock, and a gated one pays for events. Run price() with your own numbers before you budget.

When not to bother.

Tutorial: heartbeat.py.

tick() runs one check-in through the three gates. source.changes(cursor) is your adapter: it returns new items and the next cursor (Gmail history ID, Calendar sync token, an ETag, or a timestamp). run_agent() is your existing agent. price() is the cost model behind every chart above.

"""heartbeat.py: wake the expensive model only when a check-in finds work.

tick() runs one check-in: a zero-token cursor diff, then a cheap triage call on
the new items only, then the frontier agent for the few that need it.
price() compares that against calling the frontier model on every tick.
"""
import json
import random
import sys

from openai import OpenAI

TRIAGE_MODEL = "claude-haiku-5-5"
AGENT_MODEL = "claude-opus-5-5"
ALWAYS_WAKE = ("urgent", "outage", "invoice overdue", "legal")  # skip triage
VIP = {"ceo@acme.com", "oncall@acme.com"}
AUDIT = 0.05  # share of "sleep" verdicts re-checked by the agent anyway
RUBRIC = """You screen new items for a busy engineer's background agent.
Reply with JSON only: {"wake": true|false, "confidence": 0-1, "why": "..."}.
Wake if an item needs a reply, a decision, or action within 24 hours."""


def tick(source, cursors, client, run_agent):
    """One check-in. source.changes(cursor) -> (items, new_cursor)."""
    items, cursors[source.name] = source.changes(cursors.get(source.name))
    if not items:
        return "empty"                    # tier 0: no tokens spent
    if any(i["from"] in VIP or any(k in i["text"].lower() for k in ALWAYS_WAKE)
           for i in items):
        return run_agent(items, "rule")
    r = client.chat.completions.create(
        model=TRIAGE_MODEL, max_tokens=80,
        messages=[{"role": "system", "content": RUBRIC},
                  {"role": "user", "content": json.dumps(items)}])
    try:
        v = json.loads(r.choices[0].message.content)
        wake = v["wake"] or v["confidence"] < 0.7   # unsure means wake
    except (ValueError, KeyError, TypeError):
        wake = True                                 # broken triage fails open
    if wake:
        return run_agent(items, "triage")
    if random.random() < AUDIT:
        return run_agent(items, "audit")            # measures missed wakes
    return "sleep"


# $ per million tokens: Opus 5.5 in, out, cache read, 1h cache write; Haiku 5.5 in, out
OP_IN, OP_OUT, OP_READ, OP_W1H, HK_IN, HK_OUT = 4, 20, 0.20, 8, 0.10, 0.50


def price(interval_min, prefix=30_000, delta_day=24_000, active_h=12,
          out=800, events=2, rubric=1_500):
    """Monthly check-in cost per seat: every tick vs diff vs diff + triage."""
    ticks = 24 * 60 / interval_min
    live = min(ticks, active_h * 60 / interval_min)
    delta = delta_day / live
    warm = interval_min <= 60                       # 1-hour cache survives
    pre = prefix * (OP_READ if warm else OP_IN) / 1e6
    write = prefix * OP_W1H / 1e6 if warm else 0
    empty = pre + out * OP_OUT / 1e6
    full = empty + delta * OP_IN / 1e6
    every = (ticks - live) * empty + live * full + write
    diff = live * full + write
    wakes = min(events, live) + AUDIT * max(live - events, 0)
    cold = (prefix + delta) * OP_IN / 1e6 + out * OP_OUT / 1e6
    gated = live * ((rubric + delta) * HK_IN + 50 * HK_OUT) / 1e6 + wakes * cold
    return [round(x * 30, 2) for x in (every, diff, gated)]


if __name__ == "__main__":
    for m in map(int, sys.argv[1:] or [15, 30, 60, 180, 360]):
        every, diff, gated = price(m)
        print(f"every {m:>3} min  frontier every tick ${every:6.2f}  "
              f"skip empty ${diff:6.2f}  diff + triage ${gated:6.2f}  "
              f"({1 - gated / every:.0%} less)")

python heartbeat.py prints:

every  15 min  frontier every tick $ 73.44  skip empty $ 41.76  diff + triage $ 18.13  (75% less)
every  30 min  frontier every tick $ 41.76  skip empty $ 25.92  diff + triage $ 13.22  (68% less)
every  60 min  frontier every tick $ 25.92  skip empty $ 18.00  diff + triage $ 10.94  (58% less)
every 180 min  frontier every tick $ 35.52  skip empty $ 19.20  diff + triage $ 10.17  (71% less)
every 360 min  frontier every tick $ 19.20  skip empty $ 11.04  diff + triage $ 11.12  (42% less)

How to adapt it:

  1. Measure your prefix first. Log usage.input_tokens on an empty check-in. That number times your check-ins per day is your floor, and it's usually larger than teams expect once every connector's tool schema is loaded.
  2. Write one `changes()` adapter per source. Store the cursor next to the seat. If a source has no cursor, hash the newest 50 item IDs and compare. That still costs zero tokens.
  3. Keep the rubric short and the input small. Triage sees only the new items, never the agent's memory. Long rubrics bring back the prefix problem in miniature.
  4. Log every verdict with its reason. "empty", "sleep", "rule", "triage", and "audit" counts per seat per day are your cost dashboard. The audit disagreements are your quality dashboard.
  5. Run the agent on the cheapest model that handles the event. Not every wake needs Opus. "Reschedule the 3pm" is a small-model task. "Draft the renewal reply with last quarter's numbers" isn't. That's a routing decision, and it's the next gate.

Where Nadir fits.

heartbeat.py decides whether the agent wakes. Nadir decides which model handles each call once it's awake.

Gate 1 and gate 2 through one endpoint. Point the OpenAI client in heartbeat.py at Nadir's OpenAI compatible gateway and set model="auto" on the agent's calls. A trained classifier sends each request to the cheapest model you've allowed that clears your quality floor, so "reschedule the 3pm" and "draft the renewal reply" stop paying the same rate. POST /v1/bucket labels a prompt simple, medium, or complex without a provider call, which is a drop-in signal for the triage threshold.

Cost per seat, per verdict. Every response reports the model that served it and what it cost, so the empty/sleep/wake log in step 4 comes with dollar amounts attached, without a separate billing export.

Measure before you switch. Observe mode serves exactly the model you asked for and records what routing would have chosen, so you can see what gating would save on a week of real check-ins before you turn it on. With your own provider keys, Nadir charges no fee on any plan, and the provider bills you directly. Savings depend on your workload, and nothing in this post forecasts yours.

Start with a free key, or estimate your savings from your current agent spend.

Conclusion.

Always-on agents arrived in September and October 2026 as consumer products, and companies are building the same pattern into internal tools. Running one costs check-ins per day, times the price of each check-in, times seats, and the price of a check-in is mostly the agent re-reading itself. Past the cache TTL, a slower schedule can cost more, not less. Put a zero-token diff and a small-model triage in front of the frontier model, fail open, audit the sleeps, and the agent's cost follows the events instead of the clock. Then check as often as your users need.


Product facts: Anthropic's Claude Duet launch page (October 21, 2026), OpenAI's DevDay coverage of Dots (September 29, 2026), and coverage of Meta Muse's launch, all retrieved November 1, 2026. Prices are Anthropic list prices retrieved November 1, 2026: Opus 5.5 $4 input, $20 output, $0.20 cache read, 2x input for a 1-hour cache write. Haiku 5.5 $0.10 input and $0.50 output, its rate for prompts up to 100K tokens. The seat model is ours, illustrative, and not a measurement: a 30,000-token prefix, 24,000 tokens of new items a day arriving over 12 hours, 800 output tokens per frontier check-in, 2 actionable events a day, a 1,500-token triage rubric, and a 5% audit. Escalations are priced with a cold cache. Task costs after a wake are excluded and are the same in all three designs. Sources: [Anthropic, "Introducing Claude Duet"](https://claude.com/resources/articles/claude-duet). [MacRumors, "Anthropic Launches Claude Duet, a Proactive AI Agent," October 21, 2026](https://www.macrumors.com/2026/10/21/anthropic-claude-duet/). [The Decoder, "OpenAI launches always-on Dots agents to rival Meta's Muse," September 29, 2026](https://the-decoder.com/openai-launches-always-on-dots-agents-to-rival-metas-muse/). [MacRumors, "OpenAI Launches Always-On 'Dots' Agents to Rival Meta's Muse," September 29, 2026](https://www.macrumors.com/2026/09/29/openai-launches-dots/). [CNBC, "OpenAI follows Meta into the red-hot market for personal agents," September 30, 2026](https://www.cnbc.com/2026/09/30/openai-follows-meta-into-the-red-hot-market-for-personal-agents.html). [Anthropic, Pricing](https://claude.com/pricing). [Gmail API, users.history.list](https://developers.google.com/gmail/api/reference/rest/v1/users.history/list). [Google Calendar API, synchronizing resources efficiently](https://developers.google.com/calendar/api/guides/sync). [GitHub, conditional requests](https://docs.github.com/en/rest/using-the-rest-api/best-practices-for-using-the-rest-api#use-conditional-requests-if-appropriate).

More on agents

What Nadir is

Nadir is an LLM router. Nadir sends each prompt to the cheapest model that can handle it. A small decision model reads each prompt against your model menu and picks the lowest-cost model it expects to handle it. When the decision model is uncertain or unavailable, the request goes to the strongest model on the menu. The routing step makes no call to your model provider.

Nadir runs two ways. The decision API returns a model, reasoning-effort, cache, context, and policy recommendation without calling a model provider, beside the gateway you already run. That is how a shadow-mode evaluation works, and its projected savings stay advisory. The OpenAI compatible managed proxy executes the route, and migration is a two-line change: point the base URL at api.getnadir.com and set model to auto. On that path an optional verifier can score a complete non-streaming answer and escalate to a stronger model when it misses the configured bar. Streaming bypasses post-generation verification. BYOK is supported on every tier.

For coding agents, Nadir Auto is a terminal launcher for Claude Code or Codex that asks Nadir for the main-session model before each turn, with your configured model as the fallback and cost ceiling. Delegation integrations for Claude Code, Codex, or Cursor instead recommend a model tier for subagent work, and the agent decides; the Claude plugin can also move a main-thread turn to Haiku when Nadir's cache check prices it cheaper, unless its switch_main_model option is off. Either way inference runs on your own provider account, so Nadir holds no provider keys on that path.

What the numbers are, and what they are not

Nadir publishes each evaluation with its scope. On checkable code, run-check-escalate solved 392 of 395 common HumanEval and MBPP problems (99.2%), graded by running the canonical tests; that applies only to tasks with runnable deterministic tests. Nadir-Tumbler posts an arena_score of 72.3 on RouterArena's public scorer, 5th of 23 routers, which measures the routing decision on RouterArena's own model pool. A reference-assisted RouterBench evaluation over 11,420 held-out triples produced a 60% lower projected cost than always-Opus with about 98% retained quality and a 1.7% catastrophic-route rate. That experiment gave the verifier the expensive-model reference answer, which production does not have, so it is a research ceiling and not the deployed path.

None of these is a production guarantee, a universal savings rate, or a forecast for any particular workload. Customer savings are reported from measured execution against a declared baseline, and customer quality only from outcome-labelled traffic. Projected savings and realized savings are separate artifacts and are never blended.

Design-partner program

Three rungs, picked by risk appetite. Rung 0 Shadow runs advisory decision calls alongside live traffic and returns a projected receipt, with nothing in the request path changed. Rung 1 Hosted is the two-line swap on a production slice and returns a realized receipt. Rung 2 On-prem is a supervised six-week proof of concept inside the partner's VPC, where no prompt, response, or usage reaches Nadir. The commitments are the same at every rung. Apply for a rung directly: Rung 0 Shadow, Rung 1 Hosted, or Rung 2 On-prem. Not sure which fits? Start at getnadir.com/contact/?reason=design-partner.

Licensing

NadirClaw is the self-hosted core, source-available under the PolyForm Noncommercial License. Source-available is the correct label; NadirClaw is not open source. Nadir Route's hosted plan has no base fee and charges a variable fee only on measured savings from requests Nadir executed.

Pages on this site

Machine-readable summaries of this site: llms.txt and llms-full.txt.