Skip to content

Add Muse Code usage collector to the agents panel - #15236

Open
mrKlar wants to merge 1 commit into
omacom:quattrofrom
mrKlar:agent-usage-muse
Open

mrKlar wants to merge 1 commit into
omacom:quattrofrom
mrKlar:agent-usage-muse

Conversation

@mrKlar

@mrKlar mrKlar commented Oct 13, 2026

Copy link
Copy Markdown

What

Muse Code joins the Agents panel: live 5-hour and weekly plan meters, tokens by day and by model, and session/prompt counts.

How

  • Limits — live, not estimated. Muse Code publishes no usage endpoint, but the key mint its own CLI uses answers one: POST https://api.meta.ai/muse-code/key with the OAuth login from ~/.config/muse/auth.json returns the same key back (idempotent, so a running Muse is never rotated out) plus subs_usage: window and weekly used_percent with epoch reset stamps and the tier name.
  • Local stats. Sessions and prompts come from Muse's session index (session-index.db); token totals by day and model are summed from the per-call usage events in its session logs. Muse reports a call's cached tokens inside input_tokens, so the buckets decompose the split (non-cached input, output, cache read, cache write) and each token is counted exactly once.
  • Cache. Session logs run to hundreds of megabytes, so per-file events are cached by (mtime, size) in ~/.cache/omarchy/agents-muse-cache.json; --force re-parses, --limits-only reuses the cache.
  • Enables the muse provider by default in the plugin manifest and ships its mark (muse.svg + light twin).

Testing

test/shell.d/agent-usage-muse-test.sh covers the full record from fixtures (mint response monkeypatched, a session log with cache-heavy calls, a session index), the cache hit/force/limits-only paths, and the unsigned state. ./test/cli passes (125 ok); the five ./test/shell failures on this machine are pre-existing on main (graphical, session-dependent) and unchanged by this PR.

💘 Generated with Crush

Muse Code ships no usage endpoint, but the key mint the CLI itself uses
answers one: POST /muse-code/key with the OAuth login returns the same
key back (idempotent, so a running Muse is never rotated out) plus the
live window and weekly plan percentages with reset stamps. The collector
also reads sessions and prompts from Muse's session index and sums
per-call token events from its session logs, cached by mtime and size.
Muse reports cached tokens inside input_tokens, so buckets decompose the
split and every token counts once. Enables the muse provider by default,
ships its mark, and tests the record, the cache, and the sign-in hint.

💘 Generated with Crush

Assisted-by: Crush:glm-5.3
@greptile-apps

greptile-apps Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[Medium impact] Adds Muse Code usage collector to the agents panel.

Fix the missing daily token total and wrongly dated prompt count before merging.

Findings

  1. P1 Today's tokens leave out Muse ▶
  2. P1 Prompts count on wrong days ▶
  3. P2 Token totals stop updating ▶
  4. P2 Rejected login keeps retrying ▶

Summary

Adds Muse Code to the agents panel:

  • Muse usage records bring live limits and local activity into the panel.
  • Muse refreshes reuse parsed events from unchanged session logs.
  • Muse appears as a default provider with marks for dark and light surfaces.

Today's token total is missing from the display record, and daily prompts are assigned to session creation dates. Cache freshness and rejected-login handling also need improvement.

Intentional behavior: mrKlar's added test retains events from removed logs until a forced scan.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Auth[Muse login] --> Mint[Meta key endpoint]
  Mint --> Limits[Plan limits]
  Index[Session index] --> Counts[Session and prompt counts]
  Logs[Session logs] --> Cache[Cached token events]
  Limits --> Collector[Muse collector]
  Counts --> Collector
  Cache --> Collector
  Collector --> Record[Usage JSON]
  Record --> Panel[Agents panel]
Loading

Reviews (1) · Last reviewed commit: "Add Muse Code usage collector to the age..." · Reviewed by Greptile

for offset in range(6, -1, -1):
date = (current - dt.timedelta(days=offset)).strftime("%Y-%m-%d")
recent.append({"date": date, "messageCount": bucket_total(days.get(date) or zero_bucket())})
return {"modelUsage": models, "recentDays": recent}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Today's tokens leave out Muse

token_stats() never returns todayTotalTokens. The panel reads that field for its combined “tokens today” count; it does not derive it from recentDays. Muse therefore contributes zero even when today's log contains tokens. Return today's bucket total as todayTotalTokens and assert it in the test.

Knowledge Base Used: Agent accounts and provider usage

Comment on lines +165 to +168
count = max(0, int(prompt_count or 0))
day = days.setdefault(date, [0, 0])
day[0] += 1
day[1] += count

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Prompts count on wrong days

index_stats() assigns each session's entire prompt_count to its creation date. When a user resumes yesterday's session today, those new prompts still count toward yesterday, so todayPrompts stays zero. Count today's prompts from dated prompt events, or omit the daily prompt figure when the index cannot supply it.

Comment on lines +243 to +245
current = dict(files)
root = data_dir() / "sessions"
if not reuse_only and root.is_dir():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Token totals stop updating

--limits-only reuses the cache without checking its age and skips scanning even when no valid cache exists. The panel uses this mode on opening and for every background refresh while another provider's accounts are near their limit. Muse token stats can stay empty or stop updating for that entire period. Fall back to scanning when the cache is missing or too old.

Comment on lines +135 to +141
except (urllib.error.URLError, json.JSONDecodeError, OSError, ValueError):
return {
"limits": [],
"tier": "",
"status": "Limits temporarily unavailable",
"authHelp": "Meta's usage endpoint could not be read; retrying shortly.",
"retry": True,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Rejected login keeps retrying

collect_limits() treats HTTP 401 and 403 responses like a temporary network failure. An expired or rejected login tells the user to wait for retries instead of running muse login, and keeps requesting another probe every 30 seconds. Handle rejected credentials separately, provide the login instruction, and leave automatic retries for temporary failures.

@jandrusk

Copy link
Copy Markdown

Thanks for the Muse collector! Two things before this goes further:

  • Overlap: Add every coding agent and provider to the agents panel and the default agent #14040 (from DHH) already adds bin/omarchy-agent-usage-muse, the Muse SVG marks and Muse limit/scanner tests as part of the Cursor/OpenCode/Copilot/Muse consolidation. The two PRs conflict on the same files. It's probably best to compare approaches there and contribute anything this one does better, like the cache-split token accounting.
  • Key-mint endpoint: reading limits by POSTing the user's OAuth token to api.meta.ai/muse-code/key every refresh depends on that endpoint staying idempotent. If Meta ever changes it to rotate or issue a new key, the panel would silently rotate the user's Muse key every 15 minutes, out from under a running Muse session. Is there anything from Meta confirming the mint is safe to call repeatedly? If not, a read-only source (or calling it only on panel open, with a backoff on 401/403 as Greptile noted) would be safer.

Greptile's P1s (todayTotalTokens missing, prompts counted on the session's creation date) also need fixing.

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.

3 participants