Summary
Settings → Usage limits reports Claude Code as unauthenticated on macOS even when claude is logged in and ~/.claude/.credentials.json is valid JSON. The host reads the Keychain item Claude Code-credentials first, treats the blob as UTF-8 JSON, fails, and never falls through to the credentials file.
Versions and environment
- bb from source at get-bb/bb
main (eeaaa3e8db7b3aeb3c4ab46873816c84cb6ea513)
- macOS, Claude Code 2.1.x (2.1.257 observed)
- Isolated desktop instance; Claude Code logged in via OAuth (Max)
Steps to reproduce
- On macOS, log in with Claude Code 2.1.x so Keychain has
Claude Code-credentials.
- Confirm the Keychain secret is hex (
security find-generic-password -s "Claude Code-credentials" -w starts with 7b, which is {).
- Confirm
~/.claude/.credentials.json is valid JSON with claudeAiOauth.
- Open bb → Settings → Usage limits for that host, or
GET /api/v1/system/usage-limits.
Did not reproduce the unauthenticated status after decoding the Keychain blob as hex then JSON, then falling back to ~/.claude/.credentials.json.
Expected vs actual
Actual (host provider.usage for claude-code):
status: "unauthenticated"
Settings shows no Claude session/weekly/Fable windows. The Usage plugin can only render that empty/error state.
Expected: status: "ok" with the same 5-hour / weekly / model-scoped windows the Claude Code CLI shows.
Evidence
plugins/provider-claude-code/src/bridge/provider-maintenance.ts on main parses the Keychain stdout as UTF-8 JSON:
|
const parsed = claudeCredentialsSchema.safeParse(JSON.parse(raw)); |
Claude Code 2.1.x stores that Keychain password as hex-encoded JSON (7b… = {). JSON.parse throws, the file fallback is skipped because the Keychain read succeeded with a non-empty string.
A unit fixture of hex({"claudeAiOauth":{…}}) fails JSON.parse and succeeds after Buffer.from(raw, "hex").toString("utf8").
What you ruled out
- Not empty windows from a stale User-Agent (
claude-code/2.1.0) or kind === "weekly_scoped" filtering: the live API never ran because status was unauthenticated.
- Not the community Usage plugin: it only renders
GET /api/v1/system/usage-limits.
- Not a missing
~/.claude/.credentials.json: the file was valid; the Keychain path ran first and failed closed.
- Searched get-bb/bb issues for hex / keychain / unauthenticated usage-limits; no existing report of this parse.
Suggested priority and effort (optional)
High for anyone on Claude Code 2.1.x on macOS using Usage limits; workaround is none in Settings. Fix is a few lines: decode hex JSON, then fall back to the credentials file. Effort Low.
AGENT GENERATED
Summary
Settings → Usage limits reports Claude Code as unauthenticated on macOS even when
claudeis logged in and~/.claude/.credentials.jsonis valid JSON. The host reads the Keychain itemClaude Code-credentialsfirst, treats the blob as UTF-8 JSON, fails, and never falls through to the credentials file.Versions and environment
main(eeaaa3e8db7b3aeb3c4ab46873816c84cb6ea513)Steps to reproduce
Claude Code-credentials.security find-generic-password -s "Claude Code-credentials" -wstarts with7b, which is{).~/.claude/.credentials.jsonis valid JSON withclaudeAiOauth.GET /api/v1/system/usage-limits.Did not reproduce the unauthenticated status after decoding the Keychain blob as hex then JSON, then falling back to
~/.claude/.credentials.json.Expected vs actual
Actual (host
provider.usagefor claude-code):Settings shows no Claude session/weekly/Fable windows. The Usage plugin can only render that empty/error state.
Expected:
status: "ok"with the same 5-hour / weekly / model-scoped windows the Claude Code CLI shows.Evidence
plugins/provider-claude-code/src/bridge/provider-maintenance.tsonmainparses the Keychain stdout as UTF-8 JSON:bb/plugins/provider-claude-code/src/bridge/provider-maintenance.ts
Line 273 in eeaaa3e
Claude Code 2.1.x stores that Keychain password as hex-encoded JSON (
7b…={).JSON.parsethrows, the file fallback is skipped because the Keychain read succeeded with a non-empty string.A unit fixture of hex(
{"claudeAiOauth":{…}}) failsJSON.parseand succeeds afterBuffer.from(raw, "hex").toString("utf8").What you ruled out
claude-code/2.1.0) orkind === "weekly_scoped"filtering: the live API never ran because status wasunauthenticated.GET /api/v1/system/usage-limits.~/.claude/.credentials.json: the file was valid; the Keychain path ran first and failed closed.Suggested priority and effort (optional)
High for anyone on Claude Code 2.1.x on macOS using Usage limits; workaround is none in Settings. Fix is a few lines: decode hex JSON, then fall back to the credentials file. Effort Low.