Agent SDK: rate_limit_event already carries per-bucket unifiedWindows utilization at status=allowed — declare it in SDKRateLimitInfo and add a zero-token structured path (follow-up to #50518)

Status Open
Reported on v2.1.259
Maintainer reply None cached
Activity 0 comments · opened Sep 3, 2026

Summary

#50518 asked for per-bucket 5h/7d utilization for headless Agent SDK consumers and was auto-closed as inactive (and is now locked, so this is the follow-up it directs to). On the current CLI the data is already on the wire — but undocumented, and only reachable by spending a model turn.

Environment

  • Claude Code 2.1.259 (native install, linux-x64)
  • @anthropic-ai/claude-agent-sdk 0.3.257 (bundled by @agentclientprotocol/claude-agent-acp 0.73.0)
  • claude.ai subscription; utilization well below any warning threshold

Observed

One turn into a fresh session (prompt: Reply with the single word: done), the rate_limit_event's rate_limit_info — as the ACP adapter forwards it in usage_update._meta["_claude/rateLimit"]:

{
  "status": "allowed",
  "resetsAt": 1788465600,
  "rateLimitType": "five_hour",
  "overageStatus": "allowed",
  "overageResetsAt": 1790812800,
  "isUsingOverage": false,
  "unifiedWindows": {
    "five_hour": { "utilization": 0.24, "resetsAt": 1788465600 },
    "seven_day": { "utilization": 0.13, "resetsAt": 1789005600 }
  }
}
  • Top-level utilization is absent at status: "allowed", exactly as #50518 described.
  • unifiedWindows is present and populated at normal utilization — this looks like #50518's "Option A" per-bucket snapshot, shipped.
  • unifiedWindows is not declared on SDKRateLimitInfo in sdk.d.ts (0.3.257), so typed consumers cannot rely on it (#26392 asked for these types to be documented).
  • A session that only runs /usage (a local command; no API call) emits no rate_limit_event. A headless process that wants the numbers without spending a turn therefore has no structured source — /usage is rendered text.

Asks

  1. Declare unifiedWindows (with its per-bucket shape) on SDKRateLimitInfo and document it, so it is a contract rather than a wire observation.
  2. A zero-token structured path: either a control request returning the current rate-limit snapshot (getUsage() is marked EXPERIMENTAL and is not exposed over ACP), or a machine-readable form of /usage.

Why it matters

I run a usage-aware governor that seats sessions by 5h/7d headroom. Sessions launched over ACP (Zed) have no statusline, so today the only headless source is spawning the CLI and parsing /usage text hourly. It works, but it couples to UI wording; (1) plus (2) would replace it with a passive, structured source.

Reproduction: any ACP client — send one prompt and log usage_update._meta["_claude/rateLimit"]. Or via the SDK directly: log messages with type === "rate_limit_event" and inspect rate_limit_info.unifiedWindows.

View original on GitHub ↗