{"slug": "where-claude-code-codex-and-antigravity-hide-your-remaining-usage", "title": "Where Claude Code, Codex and Antigravity Hide Your Remaining Usage", "summary": "A developer published `baton-agents` to npm on September 14, four days after Sophia Myang's September 10 request for a cross-platform agent orchestration harness drew 1,024 bookmarks and 340 replies. The tool addresses the hard part of agent handoff — detecting usage limits before a session is lost — by reading Claude Code's 5-hour and 7-day utilization from the `api.anthropic.com/api/oauth/usage` endpoint (since Claude Code 2.1.268 ignores a custom `statusLine` command passed via `--settings`) and by tailing Codex's JSONL rollout file for `event_msg.token_count.rate_limits`, observed live on codex-cli 0.153.4. The author notes a third agent provides no usage signal at all, and warns that bearer tokens from `~/.claude/.credentials.json` should never be logged.", "body_md": "On September 10 someone posted this:\n\nSomeone please tell me this exists: a meta-harness + kanban board to orchestrate my agents across platforms (Claude, Codex, Grok, Muse, etc.) tracking progress and handing off projects to each other cleanly when one hits its limits. What's the best way to do this?\n\nThat's Sophia Myang. It picked up 1,024 bookmarks and 340 replies. Bookmarks are the interesting number there. A like means someone agreed. A bookmark means someone wants to come back and use the thing.\n\nShe wasn't asking me. She was asking the internet, and a thousand people bookmarked the question instead of answering it. So I built it. Four days later `baton-agents` is on npm.\n\nThis post isn't really about my thing though. It's about the part of that request nobody mentions, which is that \"hands off cleanly when one hits its limits\" requires you to know a limit is coming, and every agent tells you in a completely different way. One of them doesn't tell you at all.\n\n## The part that sounds easy and isn't\n\nThe handoff itself is a solved problem. You write the state to a file and the next agent reads it. Fine.\n\nThe trigger is the hard part. If you wait until the agent says \"you've hit your limit\" you've already lost the session, and on Claude Code you've lost it mid-tool-call. You want to move at 90%, not at 100%. Which means you need a number, continuously, from a tool that wasn't built to give you one.\n\nThree agents, three taps, and they don't resemble each other even slightly.\n\n## Claude Code: the number is there, just not where the docs point you\n\nClaude Code has a status line that shows your 5-hour and 7-day usage. The obvious move is to pass your own `statusLine` command through `--settings` and read what it prints.\n\nThat doesn't work. On 2.1.268 Claude Code renders its own built-in status line and ignores a custom `statusLine` command passed via `--settings` or a project settings file. I verified it with a plain `echo` at both levels. Hooks from that exact same settings file do run, which is what makes it confusing. You get half the file honored and half ignored, with no error.\n\nSo you skip the status line and ask the source directly:\n\n```\nGET https://api.anthropic.com/api/oauth/usage\nAuthorization: Bearer <token from ~/.claude/.credentials.json>\n```\n\nThat's the same endpoint `/usage` reads. The token is the OAuth token Claude Code already stored when you logged in, under `claudeAiOauth.accessToken`. You get back a 5-hour window and a 7-day window, each with a utilization percentage and a reset timestamp.\n\nTwo things worth saying out loud. That's your own token, on your own machine, going to the same host Claude Code already talks to. It shouldn't leave the process that reads it and it shouldn't get written to a log. Scrub bearer tokens on the way out of anything that records events.\n\nThe second signal is the `StopFailure` hook, whose error enum includes `rate_limit`. That's the wall itself rather than a warning, so it's the backstop, not the trigger.\n\n## Codex: it writes everything down, so read what it wrote\n\nCodex doesn't need a hook. An interactive `codex` session writes its entire thread to a rollout file as JSONL, flushed per event. You tail the file.\n\nThe line you want is `event_msg.token_count.rate_limits`:\n\n```\n{\n  \"primary\":   { \"used_percent\": 62.4, \"window_minutes\": 300,   \"resets_at\": \"...\" },\n  \"secondary\": { \"used_percent\": 41.1, \"window_minutes\": 10080, \"resets_at\": \"...\" }\n}\n```\n\n`primary` is 300 minutes, so that's the 5-hour window. `secondary` is 10,080 minutes, which is the week. Observed live on codex-cli 0.153.4.\n\nNot injecting a hook is a feature, not laziness. Codex prompts you to review new hooks, and a wrapper that makes your agent ask you to approve something every time you start it is a wrapper you'll uninstall.\n\nOne trap cost me real time. Codex names the day directory from local time, but the rollout's own `session_meta` timestamp is UTC. A session I started at 20:33 EDT landed in `sessions/2026/09/10` stamped `2026-09-11T00:33:44Z`. If you match the directory against the timestamp you find nothing for four hours every evening. Compare local days, and keep the previous day as slack around midnight.\n\n## Antigravity: there is no number\n\nagy is a closed Go binary. No hooks, no status line you can read, and the usage percentage genuinely is not written anywhere on disk. Its own status line fetches a quota summary from the backend and never persists it.\n\nWhat you get is `--log-file`, and strings. `RESOURCE_EXHAUSTED`, `out of quota`, `it resets in ...`. You match on those, which means you find out at the wall with no warning at all.\n\nThen there's the detail that will bite anyone who writes this quickly. The reset text looks like:\n\n```\nResets in 71h19m42s\n```\n\nGrab the first unit and you compute 71 seconds, restart the agent immediately, and hit the same wall. You have to sum every unit in the string. Three days versus seventy-one seconds is the kind of bug that looks fine in a test and wastes your evening in real life.\n\nI'll be straight about the confidence here: those limit strings are in the binary and in the docs, and I have not watched an agy limit fire live. Everything about the Claude and Codex paths above I've seen with my own eyes.\n\n## So you don't build a meter, you build three\n\nThe instinct is to normalize all this into one usage number. You can't, honestly, because the three sources don't carry the same information.\n\nClaude gives you a live percentage on two windows. Codex gives you a live percentage on two windows but only after it writes an event, so it updates in steps rather than continuously. agy gives you nothing until it's over.\n\nWhat that means in practice is that a chain should put the agents that can warn you first and the blind one last. Not because agy is worse at coding, but because you can plan around a number and you can't plan around a wall.\n\n## The handoff, once you have the trigger\n\nWith a number you can act early. The shape that works:\n\n1. Keep a context bundle current as the session runs, not at the end. A bundle written after the limit hits is a bundle written by a process that's already dead.\n2. Warn at a threshold, hand off before the wall.\n3. Start the next option in the same terminal from that bundle. Another login of the same agent if you have one, otherwise the next agent.\n4. When everything is out, say which resets first and when, then wait for it instead of failing.\n\nThat last one is a change I made after watching my own chain fail a card the moment every agent was exhausted. Failing at the limit is technically correct and completely useless. You know exactly when the window reopens, so wait for it.\n\n## What's actually verified, and what isn't\n\nI'd rather say this than have someone find it.\n\nVerified live on my machine: the Claude usage endpoint and its percentages, the `--settings` status line being ignored on 2.1.268 while hooks run, the Codex rollout shape on codex-cli 0.153.4, the local-day versus UTC directory quirk, and a forced Claude to Codex handoff continuing in the same terminal.\n\nNot verified live: a real Claude `StopFailure` rate limit firing, and every agy limit string. Those come from the CLI source and docs. They're in the code with fixtures behind them, but I haven't watched them happen.\n\nThat distinction matters more than it sounds. A limit handler you've never seen fire is a guess with good syntax.\n\n## The thing itself\n\nAll of the above is inside [baton](https://baton-agents.vercel.app/). You type `baton claude`, `baton codex` or `baton agy` instead of the bare command and get the same interactive agent, with a board next to it, the usage tap running, a bundle kept current, and the handoff when the limit lands.\n\nIt's subscription logins only. It strips `ANTHROPIC_API_KEY`, `OPENAI_API_KEY` and the rest of that family before any agent starts, because the whole point is using the plan you already pay for. It never edits your `~/.claude/settings.json` or your `~/.codex/config.toml`.\n\n```\nnpm install -g baton-agents\n```\n\nBut if you just want the three taps and you'd rather wire them yourself, they're all above. That was the actual answer to the question, and nobody in 340 replies wrote it down.", "url": "https://wpnews.pro/news/where-claude-code-codex-and-antigravity-hide-your-remaining-usage", "canonical_source": "https://www.practicalsystems.io/blog/where-coding-agents-hide-usage-limits", "published_at": "2026-09-14 00:00:00+00:00", "updated_at": "2026-09-14 22:59:19.460505+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-products"], "entities": ["Claude Code", "Codex", "baton-agents", "npm", "Sophia Myang", "Anthropic", "codex-cli 0.153.4"], "alternates": {"html": "https://wpnews.pro/news/where-claude-code-codex-and-antigravity-hide-your-remaining-usage", "markdown": "https://wpnews.pro/news/where-claude-code-codex-and-antigravity-hide-your-remaining-usage.md", "text": "https://wpnews.pro/news/where-claude-code-codex-and-antigravity-hide-your-remaining-usage.txt", "jsonld": "https://wpnews.pro/news/where-claude-code-codex-and-antigravity-hide-your-remaining-usage.jsonld"}}