Skip to content

Add Muse usage collector to the agents panel - #10610

Closed
andresantonioriveros wants to merge 4 commits into
omacom:quattrofrom
andresantonioriveros:add-muse-usage-collector
Closed

andresantonioriveros wants to merge 4 commits into
omacom:quattrofrom
andresantonioriveros:add-muse-usage-collector

Conversation

@andresantonioriveros

@andresantonioriveros andresantonioriveros commented Sep 7, 2026 •

Copy link
Copy Markdown

Muse (Meta Muse Spark) support for the Agents bar panel: a new muse collector following the claude/codex record contract, with local metering plus subscription windows.

What it adds

  • bin/omarchy-agent-usage-muse (777 lines): token, prompt, session, per-day and per-model stats from native muse CLI sessions ($XDG_DATA_HOME-aware, MUSE_DATA_DIR override) plus opencode sessions on the meta provider or muse-spark models. Subagent trees roll up into the parent session; symlinked files, symlinked directories, oversized model names/negative counts fail closed; short scan cache with locking like codex. Completions deduplicate by native record ID across session files and retained-frame children, and .msp-view* copies are excluded. Subscription windows come from the client's own key endpoint (MUSE_AUTH_PATH, else ~/.config/muse/auth.json).
  • Panel wiring: manifest.json entry, Simple Icons Meta mark (+ light-surface twin), shell/plugins/agents/README.md row + ### Muse limits section, manual/17-ai.md mention.
  • test/shell.d/agent-usage-muse-scanner-test.sh: 17 scanner tests (totals, subagent rollup, per-model buckets, run_model/retained_frame/timestamp shapes, odd timestamp/token shapes, symlinks incl. directory escape, oversized/negative values, corrupt DB, cache reuse incl. --limits-only, XDG paths).
  • test/shell.d/agent-usage-muse-limits-test.sh: 14 stub-based limits tests (subscriber percents/resets/tier, probe reuse, PAYG silence, no-snapshot tier, expired sign-in, malformed logins, MUSE_AUTH_PATH, token hygiene).
  • test/shell.d/agent-usage-muse-dedup-test.sh: 3 dedup tests (unique completions across plain records/retained frames/copied sessions, view exclusion with missing/malformed IDs still counted, pre-dedup cache rescan). By @nissuor via Why not use the 1Password AUR? #2.
  • Tier label: real subs_tier_name when subscribed, neutral Account for pay-as-you-go.
  • Auth states: Sign-in expired on 401/403, Muse limits unavailable with cached fallback on other failures, silent otherwise.

Limits: subscription windows, PAYG-aware

Since this PR opened, Muse Code GA'd subscriptions (Aug 31) and the client's key endpoint returns subs_usage session + weekly percents — the same figures as the TUI's /usage. The collector probes it additively; local metering is unchanged and always runs:

  • Subscriber with a snapshot: Session (5-hour) + Weekly (7-day) meters with resets, 60s probe cache, expired windows filtered.
  • Subscriber without a snapshot (verified live: is_subs_active:true, no subs_usage on some gateways): tier kept, Muse limits unavailable.
  • Pay-as-you-go (verified live: is_subs_active:false): silent local metering only — not an error, not expired, no retry.
  • 401/403 → Sign-in expired; transport failure → retryAdvised + cached fallback; malformed responses → generic unavailable, no retry.

Still no estimated meters from manual caps, and no per-key throttle headers: I built and live-tested an x-ratelimit-* probe and removed it — those buckets read 0% through real 429s (200+ proxy requests verified), so without an authoritative probe the panel shows measured usage only. Token travels only in the Authorization header; neither it nor the minted key is persisted.

Verification

  • Scanner 17/17 + limits 14/14 + dedup 3/3 pass (dedup fails before its fix, passes after); python3 -m py_compile + git diff --check clean; repo test/cli, bin-style, agent-usage-update, and agents-panel suites green.
  • Live: PAYG shape then subscriber shape verified on this machine (tier flips Account → plan name, meters appear once subs_usage is present); old-vs-new parity checks return identical local stats across all fields; token absent from record and caches.

Local metering (tokens, prompts, sessions, per-day and per-model
breakdowns) from native muse sessions and opencode, following the
claude/codex record contract. No limits section: the enforceable
limits are not observable locally, so none are shown.
Probe the client's own key endpoint (POST api.meta.ai/muse-code/key)
for subs_usage session + weekly percents with reset times plus the tier
name — the same figures the TUI's /usage overlay shows. Limits stay
strictly additive and authoritative:

- Subscriber with a usage snapshot: Session (5-hour) + Weekly (7-day)
  meters, cached 60s, expired windows filtered.
- Subscriber without a snapshot yet: tier kept, limits unavailable.
- Pay-as-you-go (is_subs_active=false, no subs_usage): silent local
  metering only — not an error, not expired, no retry.
- 401/403: Sign-in expired. Transport failure: retryAdvised with
  fallback. Malformed responses: generic unavailable, no retry.

No estimated meters from manual caps: without an authoritative probe
the panel shows measured usage only. The OAuth token travels only in
the Authorization header; neither it nor the minted key is persisted.

Includes a stub-based limits test (subscriber, PAYG, no-snapshot,
expired, malformed login, MUSE_AUTH_PATH) and README docs.
@nissuor

nissuor commented Sep 8, 2026 •

Copy link
Copy Markdown

I opened #10849 independently and compared the implementations. Yours has broader local usage coverage and parser handling, and I'd be happy to contribute the complementary pieces from mine here.

I just caught your latest subscription-window commit. The remaining pieces I'd propose are event-ID deduplication (including retained-frame children), exclusion of .msp-view session copies, and regression tests for both. In small fixtures, repeated event IDs and view copies currently count twice.

As a separate follow-up, mine clears limits after a failed probe rather than retaining cached percentages, while keeping local token usage visible; a later successful probe restores the meters. That behavior could be reviewed independently of the counting fixes, preserving your PAYG handling and opencode support.

Would you be open to a PR against your branch with the deduplication fixes first? If we consolidate the work here, I'm happy to close #10849 in favor of this PR.

@andresantonioriveros

Copy link
Copy Markdown
Author

Hey @nissuor! I saw the subscription documentation was updated with the new subscription and rate limits, but seems like the pay-as-you-go option most people might be using (ex. opencode zen or omarchy credit users) still doesn't report usage back.

Happy to merge those, I can undo 8f7d602 so you add a PR with subscription changes on top of this, let me know what's the best way to dedup!

@nissuor

nissuor commented Sep 8, 2026

Copy link
Copy Markdown

Thanks! No need to undo the subscription commit — I based the counting fixes directly on it: andresantonioriveros#2

The PR deduplicates valid completion record IDs across plain records, retained-frame children, and copied sessions, and excludes .msp-view* directories within the sessions tree. It also invalidates old scan caches and adds regression tests. Your opencode and PAYG behavior stays intact.

The focused Muse suites pass; the PR body documents the full-suite baseline failures on my machine. We can keep the hide-limits-on-failure behavior as a separate follow-up. Agreed that subscription windows should not be presented as coverage of hosted-proxy/PAYG throttling.

@cristianuibar

Copy link
Copy Markdown

Verified the current head on Omarchy 4.0.0.r2153.g9c5482c-1 with Muse Code 1.3.0.

Local stats are right. omarchy-agent-usage-muse --force exited 0 in about 10 seconds over the real ~/.local/share/muse/sessions tree (about 800 MB, including subagent/*/session.jsonl, excluding .msp-view*). The record is panel-ready: id muse, seven recentDays, cache subtracted out of input_tokens, reasoning not added again.

An independent count of model_completed events on the same tree is 11072 calls across 253 parent sessions. The collector reported the same 11072 prompts and 253 sessions, on muse-spark-1.3-contributor and muse-spark-1.3. Subagent calls are in the token totals and are not extra sessions. That part looks ready to merge.

The limits probe is not. On this signed-in Muse Code Power Usage account, POST https://api.meta.ai/muse-code/key returns 200 with is_subs_active: true and subs_tier_name set, and the payload has no subs_usage object at all (no window, no weekly, no used_percent). probe_key then takes the "returned no usage" branch. The PAYG silence path only runs when is_subs_active is false, so an active plan with this shape sets usageStatusText to "Muse limits unavailable" and the panel shows an error card next to otherwise good token charts.

I would treat "active subscription, no subs_usage" like the PAYG case: keep tierLabel, leave limits empty, and do not set usageStatusText. Otherwise this account type ships with a permanent warning. The token scan does not need to wait on that.

@cristianuibar

Copy link
Copy Markdown

Follow-up on the limits probe, now with a fix running locally.

The "Muse limits unavailable" card is not a transient missing snapshot on Muse Code Power Usage. POST /muse-code/key returns is_subs_active: true and subs_tier_name on every probe, and the body has no subs_usage key. The test around "Subscriber without a usage snapshot yet" encodes that shape as an error (usageStatusText == "Muse limits unavailable"). On a real Power Usage login that shape is the steady answer, so the panel keeps a red card next to valid token charts.

Treat is_subs_active: true with no subs_usage like pay-as-you-go: keep the tier, leave limits empty, do not set usageStatusText. Pay-as-you-go (is_subs_active: false) stays as it is. A response that is neither, or a subs_usage object with no windows, can still warn.

In probe_key, after the pay-as-you-go return:

tier_hint = str(payload.get("subs_tier_name") or "") if isinstance(payload, dict) else ""
if isinstance(payload, dict) and payload.get("is_subs_active") is True:
  return {"ok": False, "silent": True, "tierLabel": tier_hint}

In collect_limits, next to the pay-as-you-go return:

if probe.get("silent"):
  if probe.get("tierLabel"):
    result["tierLabel"] = probe["tierLabel"]
  return result

The snapshot test should then expect usageStatusText and authHelpText empty, tier still Muse Code Everyday Usage, and limits empty. I applied that on a local copy of this collector: the record now has tier Muse Code Power Usage, no status text, and the same 11072 prompts. The stock panel drops the red card as soon as that file is rewritten.

@cristianuibar cristianuibar left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token collection on this head is right and should land. One limits behavior will show a permanent error card on a real Muse Code Power Usage login, and the test currently requires that card. The local fix and the numbers are in the comments above. Two line notes below are the code change.

return {"ok": False, "payg": True}
tier_hint = str(payload.get("subs_tier_name") or "") if isinstance(payload, dict) else ""
return {"ok": False, "tierLabel": tier_hint,
"helpText": "Muse's usage endpoint returned no usage. Local Muse stats are still shown."}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch is what a Muse Code Power Usage account hits on every probe, not a snapshot that is about to appear. POST /muse-code/key returns is_subs_active: true and subs_tier_name, and the body has no subs_usage key at all.

Return silent here when is_subs_active is true, the same way pay-as-you-go returns early above. In collect_limits, honor silent by keeping tierLabel, leaving limits empty, and not setting usageStatusText. A response that is neither active nor pay-as-you-go can still use this help text.

The README section "Muse limits" should say an active plan with no subs_usage shows the tier and local tokens, not an error.

fail "Muse collector keeps the tier without a usage snapshot" "$nosnap"
pass "Muse collector keeps the tier without a usage snapshot"

[[ $(jq -r '.usageStatusText' <<<"$nosnap") == "Muse limits unavailable" ]] ||

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion locks in the bug. For is_subs_active: true and no subs_usage, expect usageStatusText and authHelpText to be empty, limits empty, and tierLabel still Muse Code Everyday Usage. Do not expect Muse limits unavailable.

I ran that behavior against Muse Code 1.3.0: tier Muse Code Power Usage, no status text, 11072 prompts / 253 sessions, matching an independent model_completed count. The red card in the panel went away as soon as the record was rewritten.

@andresantonioriveros

Copy link
Copy Markdown
Author

Verified the current head on Omarchy 4.0.0.r2153.g9c5482c-1 with Muse Code 1.3.0.

Local stats are right. omarchy-agent-usage-muse --force exited 0 in about 10 seconds over the real ~/.local/share/muse/sessions tree (about 800 MB, including subagent/*/session.jsonl, excluding .msp-view*). The record is panel-ready: id muse, seven recentDays, cache subtracted out of input_tokens, reasoning not added again.

An independent count of model_completed events on the same tree is 11072 calls across 253 parent sessions. The collector reported the same 11072 prompts and 253 sessions, on muse-spark-1.3-contributor and muse-spark-1.3. Subagent calls are in the token totals and are not extra sessions. That part looks ready to merge.

The limits probe is not. On this signed-in Muse Code Power Usage account, POST https://api.meta.ai/muse-code/key returns 200 with is_subs_active: true and subs_tier_name set, and the payload has no subs_usage object at all (no window, no weekly, no used_percent). probe_key then takes the "returned no usage" branch. The PAYG silence path only runs when is_subs_active is false, so an active plan with this shape sets usageStatusText to "Muse limits unavailable" and the panel shows an error card next to otherwise good token charts.

I would treat "active subscription, no subs_usage" like the PAYG case: keep tierLabel, leave limits empty, and do not set usageStatusText. Otherwise this account type ships with a permanent warning. The token scan does not need to wait on that.

Taking a look. Thanks for reviewing this and the detailed pointers!

Active plans that return no subs_usage (Muse Code Power Usage answers
this way on every probe) are a steady state, not a missing snapshot:
keep the tier, show local metering only, no error card. Unknown shapes
without is_subs_active still warn.
@dhh

dhh commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Thank you! Brought in with your authorship in #14040, with kept limits marked stale after a failed check, OpenCode V2 sessions read, and Zen's Muse Spark left to the OpenCode record.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants