Add Muse provider (Meta Muse) - #3340
Conversation
- Add UsageProvider.muse with descriptor, settings, fetcher - Support META_API_KEY / MUSE_API_KEY and CLI probe (muse --version) - Probe api.meta.ai/v1/usage candidates with fallback to identity card - Add BinaryLocator.resolveMuseBinary, icon, docs, manifests (70 providers) - Update README and providers overview
|
🦞👀 Pull request received. I will update this pull request when review starts. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7cc7f8b2cc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| baseURL.appendingPathComponent("usage"), | ||
| baseURL.appendingPathComponent("billing/usage"), | ||
| baseURL.appendingPathComponent("me"), | ||
| URL(string: "https://api.meta.ai/v1/usage")!, |
There was a problem hiding this comment.
Keep overridden credentials on the configured host
When MUSE_BASE_URL points to a custom endpoint and its candidate routes return 404/501, unusable JSON, or a network error, this unconditional fallback sends the same bearer credential to api.meta.ai. A key intended only for a proxy, test server, or enterprise endpoint is therefore disclosed to an unrelated host; candidate URLs should remain relative to the configured base URL unless the base URL is the default Meta host.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed — the unconditional api.meta.ai candidate is gone, along with the whole
candidate list. With a valid key those paths return 404 (identical to a
nonexistent path), so they were never real endpoints.
MUSE_BASE_URL now resolves through the existing ProviderEndpointOverrideValidator
seam and throws MuseUsageError.invalidEndpointOverride instead of falling back to
Meta, so a key scoped to a private gateway cannot reach api.meta.ai. Two tests
pin it: "rejected base URL override never falls back to the Meta host" and
"fetch keeps the credential on the configured host".
| let loginCheck = ShellCommand.run(binary, args: ["auth", "--help"], timeoutSeconds: 5) | ||
| let isAuthenticated = loginCheck.exitCode == 0 |
There was a problem hiding this comment.
Do not treat help output as an authentication check
When the Muse binary is installed but the user has never logged in, muse auth --help can still exit successfully because it only displays command help; the accompanying docs/muse.md:17 likewise describes it as a reachability check. Setting isAuthenticated from that exit status bypasses the missing-credentials error and reports a successful “Muse CLI” identity for an unauthenticated installation, so this needs an actual noninteractive auth-status or credential check.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed, and confirmed against the real CLI: muse auth only offers auth set —
there is no non-interactive auth-status command, so the help-exit-code check
could never have been correct.
Login state now comes from ~/.config/muse/auth.json, which muse login writes.
It also yields the real account email and login mechanism, so the identity card
is populated rather than empty. Only the plaintext metadata is read; the
credential itself stays in the Keychain and is never touched, so refreshing Muse
cannot raise a Keychain prompt. docs/muse.md is corrected too — it previously
claimed Keychain storage, which was wrong.
The Meta Model API publishes no usage, billing, or account endpoint, so the previous probe guessed at /usage, /billing/usage and /me and presented an "API Key" card whenever they failed. Replace the guesswork with the rate-limit headers Meta documents, read from one GET /v1/models so a refresh never spends tokens. - Derive tokens-per-minute and requests-per-minute windows from x-ratelimit-limit/remaining-tokens/requests. - Keep the credential on the configured host: drop the hardcoded api.meta.ai candidate, and validate MUSE_BASE_URL like every other provider endpoint instead of silently falling back to Meta. - Surface transport, server and endpoint failures instead of reporting a configured-and-healthy provider. - Read account identity from ~/.config/muse/auth.json, which muse login writes, rather than inferring login state from `muse auth --help` (it exits 0 whether or not anyone is logged in). Only the plaintext metadata is parsed, so no Keychain prompt is possible. - Drop the local process runner in favour of no CLI spawn at all, which also removes the Muse binaryLocator the architecture gatekeeper rejects. - Accept the documented MODEL_API_KEY alongside META_API_KEY, drop the invented MUSE_API_KEY, and fix the dashboard, changelog and status links. - Remove the unreachable museBaseURL setting and the empty token-load stub. - Add MuseProviderTests and refresh docs/muse.md.
|
Codex review: needs maintainer review before merge. Reviewed September 1, 2026, 10:24 AM ET / 14:24 UTC. ClawSweeper reviewWhat this changesThe PR adds a Muse provider that validates Meta API keys and reads local Muse session logs to show account identity and daily token usage without inventing a quota. Merge readinessThe prior findings are resolved and the final head has no discrete correctness defect; this remains open for explicit owner approval because it adds a supported core provider and an ongoing third-party local-log contract. Priority: P2 Review scores
Verification
How this fits togetherCodexBar collects provider credentials, account status, and local usage into shared menu-bar and dashboard views. Muse inputs local CLI metadata, session logs, and an optional API key, then emits identity and token snapshots through the common provider registry. flowchart LR
A[Muse login metadata] --> C[Muse provider]
B[Muse session logs] --> D[Local token reader]
E[Optional API key] --> C
C --> F[Account identity]
D --> G[Daily token snapshot]
F --> H[CodexBar menu and dashboard]
G --> H
Decision needed
Why: The implementation is coherent and no replacement core path exists, but adding a provider creates an ongoing product and maintenance commitment that code review cannot make on behalf of the repository owner. Before merge
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Approve and maintain the native Muse provider only if core support for its local-log contract is desired; otherwise keep the existing provider architecture unchanged rather than landing an unsupported surface. Do we have a high-confidence way to reproduce the issue? Not applicable as a bug reproduction: this PR adds a provider rather than repairing an established broken behavior. The contributor did supply live API observations and a frozen real-log parsing comparison for the new behavior. Is this the best way to solve the issue? Yes, conditionally: it follows CodexBar’s existing descriptor and local-token-reader patterns and fixes all retained prior findings, but only a maintainer can decide whether Muse belongs in the supported core provider set. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against eb290548a739. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (3 earlier review cycles)
|
Muse Code records every model turn to ~/.local/share/muse/sessions/<Y>/<M>/<D>/<session>/session.jsonl, so CodexBar can build the same local token history it already derives for Claude and Codex, with no network call, no credential and no Keychain access. This replaces the placeholder card with real numbers. Token semantics were checked against 1,431 recorded events: reasoning_tokens is a subset of output_tokens, and cached_tokens/cache_read_tokens are subsets of input_tokens and always equal each other. A turn therefore totals input + output; summing the cache or reasoning counters would double-count, in one sampled turn by 41,201 tokens against a 41,231-token input. The automated_review_completed shape carries its own total_tokens, which matched input + output in every observed event. Two record kinds also carry a usage object and are excluded: resource_usage_sampled holds CPU and RSS gauges, and workflow_child_lifecycle repeats a child's turns. An unrecognized kind carrying token counts downgrades coverage instead of vanishing from the totals. Scanning stays cheap on large trees. Day directories outside the history window are skipped unopened, lines without an input_tokens field are rejected before JSON parsing, and each file's size, mtime and per-day totals are cached so an unchanged log is never reread. On an 883 MB tree of 4,388 logs a cold scan took 16s and a warm scan 0.26s, for totals identical to an independent reference implementation. A scan that exhausts its budget keeps the files it finished, so the next refresh resumes. No quota is shown. Every usage, billing and account path returns 404 with a valid key, and the documented x-ratelimit-* headers ride only on billed inference responses, so reading them would spend tokens on every refresh and consume the limit being reported. The API key is now used only to validate itself against GET /v1/models. Also register Muse in the architecture gatekeeper, the token-account credential catalog and the dashboard cost contract, which the provider needed and did not have.
|
@clawsweeper re-review Both P1 and P2 are fixed, and the PR now carries the behavioural proof that was
On the speculative-contract concern: rather than guessing, the provider was So the rate-limit headers exist only on billed inference, and no usage endpoint Reader output vs an independent reference implementation on a frozen 883 MB |
|
🦞🧹 I asked ClawSweeper to review this item again. |
The cache aggregated each log's turns into per-day totals before storing them, so overlap could only be resolved whole-file: a log holding one already-counted event alongside unique ones was dropped entirely, silently under-reporting. Store one row per recorded turn instead. Deduplication now skips exactly the repeated ids and keeps the rest, and a partial-overlap regression covers it. Totals on a frozen 883 MB tree are unchanged (1,235 requests, 113,824,253 tokens); the warm scan stays at ~0.2s. Also correct the local strategy's diagnostic. It still advised setting META_API_KEY for usage, left over from the earlier rate-limit design; usage comes from the local logs and an API key only validates identity.
|
Both findings fixed in 6a2d063. Deduplicate individual events, not an entire overlapping log — correct, and Totals on the frozen 883 MB tree are unchanged after the rewrite Correct the local-source remediation message — fixed. It now reads swiftlint --strict 0 violations, swiftformat clean, manifests 70, doc links 191, |
The cache moved to per-event rows in v2; docs still named v1 and per-day totals.
|
P3 fixed in 9d37b79 — Full suite runGitHub Actions is gated on maintainer approval for this fork PR 986 discovered selections. The single failure is One note for anyone else running that harness on macOS: Still unverified on my side and worth CI confirming: the build on CI's Swift |
|
Meta added subscriptions for Muse Code with included usage, would be cool to integrate it |
Adds Muse (Meta Muse Code) as provider #70.
Muse reports local token usage, read from the session logs the CLI writes.
It reports no quota — Meta publishes no endpoint for one, verified below.
Where the numbers come from
Muse Code records every model turn to
~/.local/share/muse/sessions/<Y>/<M>/<D>/<session>/session.jsonl, so CodexBarderives the same local token history it already builds for Claude and Codex —
no network call, no credential, no Keychain access.
Token semantics were verified across 1,431 recorded events, without exception:
reasoning_tokens≤output_tokenscached_tokens≤input_tokenscached_tokens==cache_read_tokensA turn totals
input + output. Summing the cache or reasoning counters woulddouble-count — one sampled turn reported 41,201 cached tokens against a
41,231-token input.
automated_review_completedcarries its owntotal_tokens,which equalled
input + outputin every observed event.Two record kinds also carry a
usageobject and are excluded:resource_usage_sampled(CPU/RSS gauges, not tokens — 4,393 of them against1,235 real turns) and
workflow_child_lifecycle(a child's rollup, alreadyrecorded on its own). An unrecognized kind carrying token counts downgrades
coverage to partial rather than vanishing from the totals.
Why there is no quota
With a valid API key, every usage-shaped path returns
404— identical to apath that does not exist:
/v1/usage,/v1/billing/usage,/v1/me,/v1/account,/v1/credits,/v1/limits,/v1/quota, …/v1/zzz_nonexistent/v1/modelsThe documented
x-ratelimit-*headers are real, but ride only on billedinference responses:
Reading them would mean issuing a billed completion on every refresh, which
would also consume the limit it reports; and being per-minute, they read at ~0%
except mid-burst. So the API key is used only to validate itself against the
free
GET /v1/models(200 vs 401).Scanning cost
An 883 MB tree of 4,388 logs: cold scan 16 s, warm scan 0.26 s, identical
totals. Day directories outside the history window are skipped unopened, lines
without an
input_tokensfield are rejected before JSON parsing, and eachfile's size/mtime/per-day totals are cached. A budget-exhausted scan keeps the
files it finished and resumes next refresh.
Verification
a frozen snapshot — identical to the token:
1,235 requests · 112,776,365 in · 1,047,888 out · 113,824,253 totalswiftlint --strict→ 0 violations / 2,090 filesswiftformat --lint→ 0 files need formattingScripts/regenerate-provider-manifests.sh --check→ 70 providerscheck-documentation-links.mjs→ 191 links ·check-app-locales.mjs→ OKReview feedback
Both Codex findings are fixed, and the code they referenced is gone:
api.meta.aicandidate is removed.MUSE_BASE_URLnow goes throughProviderEndpointOverrideValidatorandthrows rather than falling back to Meta. Pinned by two tests.
muse auth --helpas auth check —muse authonly offersauth set;there is no non-interactive status command. Login state now comes from
~/.config/muse/auth.json, which also supplies the real account email. Onlythe plaintext metadata is parsed, so no Keychain prompt is possible.
Also registered Muse in the architecture gatekeeper, the token-account
credential catalog and the dashboard cost contract — all three were missing and
would have failed CI.