Files
lumbridge-code/scripts/claude-statusline-bridge.py
Metal AgentandClaude Opus 5 ef52aa7ce2 Replace the footer's placeholder usage with a real observation ledger
The footer showed invented percentages. It now shows what two harnesses
actually report, or says it does not know.

lumbridge-core gains an append-only per-profile UsageLedger and a projection
that labels every derived value estimated, withholds a burn rate from a single
sample, withholds a window fraction with no reported ceiling, withholds an
exhaustion estimate that lands after the reset, and reports an expired window
as rolled over rather than freezing its last percentage. A missing fact renders
as missing, never as zero. (0012)

lumbridge-harness is the impure side: processes, clocks, and untrusted wire
text in, observations out. Three adapters:

- Codex's account/rateLimits/read over the app-server's JSON-RPC stdio. The
  client cannot express a request outside a two-variant enum and answers every
  server-to-client request with -32601, so a harness asking Lumbridge for a
  credential is refused by construction. (0013)
- Claude Code's session transcripts, as a byte-offset tail follower that
  reports nothing until the backlog is read to EOF — a partially-read backlog
  is indistinguishable from a burst of spend, and the first run against 20 MB
  reported forty-six billion tokens an hour. The parser models four counters,
  so the conversations in those files are not representable. (0014)
- Claude Code's five-hour and seven-day subscription windows, via a bridge
  installed as its statusLine command. 0014 had claimed no such surface
  existed; it does, and the record is corrected in place rather than quietly
  edited. Lumbridge does not read the OAuth credential to call the account
  usage endpoint, which is what comparable tools do — AGENTS.md forbids it,
  and 0015 says so rather than leaving the gap unexplained.

Also in here: a capability-check ordering fix in the workspace reducer, where
the applied-request replay table was consulted before the capability check and
so answered questions the caller had no right to ask; the GPUI spike wired to
the live probes with per-harness gauges and provenance chips; and a launcher
that matches its own window by PID, because GPUI sets WM_NAME but not
_NET_WM_NAME and a title match never succeeded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 21:47:11 -07:00

109 lines
3.6 KiB
Python

"""Extract Claude Code's rate-limit windows from a status-line payload.
Invoked by `claude-statusline-bridge.sh` with the feed path as argv[1] and the
status-line JSON on stdin. Appends only the rate-limit fields to the feed and
prints a status line.
Must never fail: a status-line command that errors degrades the user's Claude
Code session, so every step is guarded and this always exits 0 having printed.
"""
import json
import os
import sys
# Keep the feed bounded. The probe only needs the newest line; older ones are
# superseded snapshots, not history worth keeping.
MAX_FEED_BYTES = 256 * 1024
WINDOW_NAMES = ("five_hour", "seven_day")
PERCENT_KEYS = ("used_percentage", "utilization", "resets_at")
def extract(payload):
"""Return the record to append: rate-limit fields and nothing else.
The payload also carries the session's cost, transcript path, working
directory, and model. None of that is Lumbridge's business, and none of it
is copied — this builds a fresh dict rather than filtering the original.
"""
record = {"rate_limits_available": payload.get("rate_limits_available")}
limits = payload.get("rate_limits")
if not isinstance(limits, dict):
return record
windows = {}
for name in WINDOW_NAMES:
window = limits.get(name)
if not isinstance(window, dict):
continue
kept = {
key: window[key]
for key in PERCENT_KEYS
if isinstance(window.get(key), (int, float))
and not isinstance(window.get(key), bool)
}
if kept:
windows[name] = kept
if windows:
record["rate_limits"] = windows
return record
def status_line(record):
if record.get("rate_limits_available") is False:
return "lumbridge · no plan limits on this account"
windows = record.get("rate_limits")
if not windows:
return "lumbridge · no window reported yet"
parts = []
for name, label in (("five_hour", "5h"), ("seven_day", "7d")):
window = windows.get(name)
if not window:
continue
percent = window.get("used_percentage", window.get("utilization"))
if percent is None:
continue
parts.append(f"{label} {max(0.0, 100.0 - float(percent)):.0f}% left")
if not parts:
return "lumbridge · no window reported yet"
return "lumbridge · " + " · ".join(parts)
def append(feed, record):
if not feed:
return
try:
# Rotate rather than grow without bound. The probe resets its read
# offset when the file shrinks, so a rotation costs one reading.
if os.path.exists(feed) and os.path.getsize(feed) > MAX_FEED_BYTES:
open(feed, "w").close()
# Append so concurrent Claude Code sessions do not clobber each other;
# a short line written in append mode lands intact.
with open(feed, "a") as handle:
handle.write(json.dumps(record, separators=(",", ":")) + "\n")
except Exception:
pass # A feed we cannot write is not worth breaking a session over.
def main():
feed = sys.argv[1] if len(sys.argv) > 1 else ""
try:
payload = json.load(sys.stdin)
except Exception:
print("lumbridge · unreadable status payload")
return 0
if not isinstance(payload, dict):
print("lumbridge · unreadable status payload")
return 0
record = extract(payload)
append(feed, record)
print(status_line(record))
return 0
try:
sys.exit(main())
except Exception:
# Last resort: never let a status line take a session down.
print("lumbridge")
sys.exit(0)