Skip to content

feat(provider): add Muse local token usage - #3371

Closed
krazybean wants to merge 1 commit into
steipete:mainfrom
krazybean:feat/muse-provider-upstream
Closed

feat(provider): add Muse local token usage#3371
krazybean wants to merge 1 commit into
steipete:mainfrom
krazybean:feat/muse-provider-upstream

Conversation

@krazybean

Copy link
Copy Markdown
Contributor

Summary

Adds Muse as a first-class CodexBar provider with local token and request usage history derived from Muse session telemetry.

Muse does not currently expose subscription quota, reset-window, or billing/cost data suitable for CodexBar's normal quota model, so this integration intentionally reports token history only rather than fabricating quota or spend information.

How it works

Muse stores local session telemetry under its session directory as JSONL records. The provider scans runtime.session / model_completed events and aggregates:

  • Input tokens
  • Output tokens
  • Cache-read tokens
  • Reasoning tokens
  • Request counts
  • Model attribution
  • Daily usage history

model_completed is treated as the authoritative usage event. goal_usage_attribution records are deliberately ignored to avoid double-counting the same completion.

Both the direct JSONL format and Muse's wrapped retained_frame / record_json format are supported.

The scanner only extracts usage telemetry required for aggregation; prompt, source, and tool-output contents are not surfaced through the provider.

Incremental session cache

Muse session histories can become quite large, so rescanning every session file on each CodexBar refresh is impractical.

This adds a persistent incremental cache for Muse session usage. It tracks per-file state and daily/model contributions so subsequent refreshes can:

  • Reuse unchanged files without reopening them
  • Parse only newly appended JSONL content
  • Detect truncation or replacement and reparse safely
  • Remove contributions from deleted or expired files
  • Rebuild safely after timezone changes or corrupt/incompatible cache state
  • Avoid persisting partially updated state if a scan is cancelled

File replacement detection includes a lightweight prefix fingerprint so a larger file replacing an existing session at the same path is not mistaken for an append.

JSONL boundary handling also preserves incomplete trailing writes for the next scan while consuming complete final records correctly.

On a local Muse history containing ~9,500 session files / ~5.8 GB of session data, an initial scan is necessarily expensive, but unchanged warm refreshes drop to roughly 3–4 seconds with zero session files reopened.

Provider behavior

Muse intentionally exposes:

  • Token usage history
  • Request history
  • Model attribution

Muse intentionally does not expose:

  • Fabricated subscription quotas
  • Fabricated reset windows
  • Estimated dollar spend without authoritative pricing data

This follows CodexBar's existing token-history path for providers where local token telemetry is available without corresponding quota/cost information.

Tests

Adds coverage for:

  • model_completed usage extraction
  • goal_usage_attribution double-count prevention
  • Cache/reasoning token accounting
  • Epoch-microsecond timestamp bucketing
  • Malformed/unrelated records
  • Sensitive payload fields not affecting telemetry parsing
  • Subagent session discovery
  • Lookback/date-directory pruning
  • Wrapped record_json records
  • Incremental append parsing
  • Unchanged-file cache reuse
  • New/deleted/truncated session files
  • Larger same-path file replacement
  • Incomplete trailing JSONL writes
  • Cache expiration/pruning
  • Timezone invalidation
  • Corrupt cache recovery
  • Atomic cache writes
  • Cancellation safety

MuseLocalSessionScannerTests: 13/13 passing.

The incremental cache regression tests also pass individually; one cancellation test can encounter a swiftpm-testing-helper signal 5 issue in the local Swift Testing environment, despite the underlying synchronous cancellation path completing correctly.

Configuration

Session root resolution supports:

  1. MUSE_HOME
  2. CODEXBAR_MUSE_HOME
  3. Muse's default local data location

Muse CLI version detection is also included for provider metadata.

Scope

This PR is limited to the Muse provider and its local usage/cache implementation.

Changes needed to support packaging CodexBar forks with non-upstream Developer ID identities are intentionally kept in a separate PR.

@clawsweeper

clawsweeper Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c74100a70

ℹ️ 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".

Comment on lines +521 to 522
case .grok, .muse:
return self.grokLocalTokenSnapshot(from: snapshot, historyDays: windowDays)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep Muse from falling back to Grok token data

When the Muse presentation snapshot is temporarily nil while a Grok token snapshot is cached, routing .muse through grokLocalTokenSnapshot returns self.tokenSnapshots[.grok]; the Muse card can therefore display Grok token and request history. Pass the provider into the helper or use a Muse-specific projection so a missing Muse snapshot remains empty.

AGENTS.md reference: AGENTS.md:L46-L46

Useful? React with 👍 / 👎.

Comment on lines +57 to +64
if dateDirs.isEmpty {
// Prune old data even when no date dirs exist
self.pruneExpired(cache: &cache, scanSinceKey: scanSinceKey, scanUntilKey: scanUntilKey, calendar: calendar)
// Only save if not cancelled
try checkCancellation?()
cache.lastScanUnixMs = Int64(now.timeIntervalSince1970 * 1000)
MuseSessionCostCacheIO.save(cache: cache, cacheRoot: cacheRoot, calendar: calendar)
let summary = self.summaryFromCache(cache: cache, calendar: calendar, sinceKey: scanSinceKey, untilKey: scanUntilKey, now: now, fileCount: 0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove cached usage when all date directories disappear

If the last relevant Muse date directory is deleted, dateDirs becomes empty and this early return only prunes out-of-window entries; cached files and contributions within the current window are never checked for deletion. The provider will continue reporting the deleted sessions, potentially for the remainder of the lookback window, so the empty-directory path must also invalidate missing cached files.

Useful? React with 👍 / 👎.

Comment on lines +13 to +14
let costUsage = summary?.toCostUsageTokenSnapshot(
historyDays: MuseLocalSessionScanner.defaultLookbackDays)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the configured Muse history length

For any non-default history setting, the fetch strategy scans context.costUsageHistoryDays but this conversion always labels the result as 30 days. In particular, a 90-day scan is subsequently projected by grokLocalTokenSnapshot with historyCoverageIsEstablished == false because the published historyDays is only 30, preventing downstream dashboard coverage calculations from recognizing the complete history. Carry the requested history length into MuseUsageSnapshot instead of restoring the default.

Useful? React with 👍 / 👎.

}
private static func parseMuseSessionFileDelta(fileURL: URL, startOffset: Int64, calendar: Calendar, lookbackCutoff: Date) -> MuseParseResult {
var result = MuseParseResult()
guard let fullData = try? Data(contentsOf: fileURL) else { return result }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Read only the appended range during incremental scans

When startOffset > 0, this still loads the entire session file before taking a suffix; the append path also reads the whole file for fingerprints before and after this call. Consequently, every append to a large active session performs multiple full-file reads and allocations rather than work proportional to the new JSONL content, which can cause large memory and I/O spikes. Seek to startOffset and hash/read bounded ranges instead.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Sep 2, 2026
@clawsweeper

clawsweeper Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed September 1, 2026, 8:41 PM ET / September 2, 2026, 00:41 UTC.

ClawSweeper review

What this changes

Adds an opt-in Muse provider that scans local Muse session JSONL files, caches token/request history, and displays token-only usage in CodexBar.

Merge readiness

Blocked until real behavior proof is added - 12 items remain

Keep open: this is a useful opt-in provider feature, but it currently can show Grok data as Muse data and has three additional correctness/performance defects; it also needs real Muse-session proof and maintainer product approval.

Priority: P2
Reviewed head: 4c74100a708689c7aa9d3460196bbe1507e515f0
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The feature has substantial focused test coverage but remains merge-blocked by one P1 data-isolation bug, three P2 defects, and absent real behavior proof.
Proof confidence 🧂 unranked krab (1/6) Needs real behavior proof before merge: The changed production path is the Muse local-session scanner feeding the provider card, but the PR supplies only test claims and no redacted after-fix CodexBar run against real Muse telemetry showing the observed token history. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🦪 silver shellfish (2/6) 4 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs real behavior proof before merge: The changed production path is the Muse local-session scanner feeding the provider card, but the PR supplies only test claims and no redacted after-fix CodexBar run against real Muse telemetry showing the observed token history. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 6 items Cross-provider fallback: The introduced .muse branch calls a Grok-specific helper; when the supplied Muse snapshot is nil, that helper falls back to the cached .grok snapshot.
Existing helper provenance: The Grok helper's fallback to tokenSnapshots[.grok] was introduced by the current token-history implementation, confirming it is provider-specific rather than a generic projection helper.
Deleted-root cache path: When no date directories remain, the introduced early return prunes only out-of-window data and returns before checking cached in-window files for deletion.
Findings 4 actionable findings [P1] Route Muse through its own token snapshot
[P2] Invalidate cached usage when the final date directory is removed
[P2] Preserve the requested Muse history length
Security None None.

How this fits together

CodexBar provider descriptors fetch usage data and publish snapshots to the shared Usage & Spend UI. This PR adds a local Muse-log scanner and cache that feed Muse token history into that snapshot pipeline.

flowchart LR
A[Muse session JSONL files] --> B[Local Muse scanner]
B --> C[Incremental usage cache]
C --> D[Muse usage snapshot]
D --> E[Usage and Spend projection]
E --> F[CodexBar provider card]
Loading

Decision needed

Question Recommendation
Should CodexBar formally support an opt-in local Muse telemetry scanner as a first-class provider after the concrete defects and proof gap are resolved? Approve the provider direction: Keep the feature after the listed repairs and redacted real-session proof establish a safe token-only integration.

Why: This adds a durable provider, environment-variable configuration, local cache, and support surface; code repair alone cannot establish whether that product commitment is desired.

Before merge

  • Add real behavior proof - Needs real behavior proof before merge: The changed production path is the Muse local-session scanner feeding the provider card, but the PR supplies only test claims and no redacted after-fix CodexBar run against real Muse telemetry showing the observed token history. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Route Muse through its own token snapshot (P1) - The new Muse branch calls grokLocalTokenSnapshot; if the supplied Muse snapshot is nil, that helper falls back to tokenSnapshots[.grok], so the Muse card can show Grok usage. Pass the provider to a generic helper or add a Muse-specific projection that never falls back to Grok.
  • Invalidate cached usage when the final date directory is removed (P2) - When deleting the final current-window date directory, dateDirs is empty and this return skips the later missing-file cleanup. Cached contributions therefore remain visible until they age out; purge in-window cached files that no longer exist before returning.
  • Preserve the requested Muse history length (P2) - The fetch scans context.costUsageHistoryDays, but this conversion always publishes 30 days. A longer configured scan is then marked as incomplete by the shared projection; carry the requested window into MuseUsageSnapshot.
  • Read only the appended range (P2) - The append path reads the entire file for the prefix check, again in parseMuseSessionFileDelta, and again for the refreshed fingerprint. This defeats the stated incremental behavior for large active sessions; seek and hash/read bounded ranges instead.
  • Resolve merge risk (P1) - Merging now can display cached Grok token and request history on a Muse card when a Muse refresh has no snapshot.
  • Resolve merge risk (P1) - Deleting the final in-window Muse date directory leaves cached usage visible, and active large session files are reread in full on every append.
  • Resolve merge risk (P1) - The public feature contract and real telemetry compatibility have not yet been demonstrated against a redacted Muse installation.
  • Improve patch quality - Fix the provider-specific snapshot routing and preserve the configured history window with focused regression tests.
  • Improve patch quality - Handle deletion of the final date directory and change append processing to bounded reads.
  • Improve patch quality - Add a redacted terminal capture, runtime log, or recording of CodexBar loading real Muse session telemetry; updating the PR body should trigger re-review, or ask a maintainer to comment @clawsweeper re-review.

Findings

  • [P1] Route Muse through its own token snapshot — Sources/CodexBar/UsageStore+TokenCost.swift:521-522
  • [P2] Invalidate cached usage when the final date directory is removed — Sources/CodexBarCore/Providers/Muse/MuseLocalSessionScanner.swift:57-65
  • [P2] Preserve the requested Muse history length — Sources/CodexBarCore/Providers/Muse/MuseUsageSnapshot.swift:12-14
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Implementation and test delta production +848/-2, tests +1,038, docs +1/-1 The feature adds a 556-line scanner and a persistent cache, so the four uncovered integration defects materially affect a large new surface.

Merge-risk options

Maintainer options:

  1. Repair the provider path before merge (recommended)
    Isolate Muse snapshots, preserve the requested history window, handle an empty date-root deletion, and stream append reads with focused regression coverage.
  2. Defer the new provider
    Pause the feature if maintainers do not want to own compatibility with Muse's local telemetry layout and cache behavior.

Technical review

Best possible solution:

Retain an opt-in, token-only Muse provider only after its projection is provider-isolated, its cache handles complete directory removal with bounded append reads, configured history is preserved, and a real Muse run verifies the resulting card/history.

Do we have a high-confidence way to reproduce the issue?

Yes—source-reproducible: a nil Muse snapshot plus a cached Grok snapshot takes the introduced branch into the Grok fallback, and complete removal of the only date directory takes the cache early-return path.

Is this the best way to solve the issue?

No—the current reuse of a Grok-specific projection violates provider data isolation; Muse needs its own snapshot projection while preserving the caller-selected history window and cache invariants.

Full review comments:

  • [P1] Route Muse through its own token snapshot — Sources/CodexBar/UsageStore+TokenCost.swift:521-522
    The new Muse branch calls grokLocalTokenSnapshot; if the supplied Muse snapshot is nil, that helper falls back to tokenSnapshots[.grok], so the Muse card can show Grok usage. Pass the provider to a generic helper or add a Muse-specific projection that never falls back to Grok.
    Confidence: 0.99
  • [P2] Invalidate cached usage when the final date directory is removed — Sources/CodexBarCore/Providers/Muse/MuseLocalSessionScanner.swift:57-65
    When deleting the final current-window date directory, dateDirs is empty and this return skips the later missing-file cleanup. Cached contributions therefore remain visible until they age out; purge in-window cached files that no longer exist before returning.
    Confidence: 0.98
  • [P2] Preserve the requested Muse history length — Sources/CodexBarCore/Providers/Muse/MuseUsageSnapshot.swift:12-14
    The fetch scans context.costUsageHistoryDays, but this conversion always publishes 30 days. A longer configured scan is then marked as incomplete by the shared projection; carry the requested window into MuseUsageSnapshot.
    Confidence: 0.98
  • [P2] Read only the appended range — Sources/CodexBarCore/Providers/Muse/MuseLocalSessionScanner.swift:87-99
    The append path reads the entire file for the prefix check, again in parseMuseSessionFileDelta, and again for the refreshed fingerprint. This defeats the stated incremental behavior for large active sessions; seek and hash/read bounded ranges instead.
    Confidence: 0.97

Overall correctness: patch is incorrect
Overall confidence: 0.99

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 2cac84440c42.

Labels

Label changes:

  • add P2: This is an opt-in provider feature with concrete incorrect token-history behavior, but it is disabled by default and does not affect existing providers.
  • add merge-risk: 🚨 other: The PR can publish stale or misattributed local usage data despite passing normal parser tests.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The changed production path is the Muse local-session scanner feeding the provider card, but the PR supplies only test claims and no redacted after-fix CodexBar run against real Muse telemetry showing the observed token history. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: This is an opt-in provider feature with concrete incorrect token-history behavior, but it is disabled by default and does not affect existing providers.
  • merge-risk: 🚨 other: The PR can publish stale or misattributed local usage data despite passing normal parser tests.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The changed production path is the Muse local-session scanner feeding the provider card, but the PR supplies only test claims and no redacted after-fix CodexBar run against real Muse telemetry showing the observed token history. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Evidence

What I checked:

Likely related people:

  • Peter Steinberger: Raw commit 41d904f adds Sources/CodexBar/Providers/Grok/UsageStore+GrokLocalSessions.swift:9 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 41d904fd6d88; files: Sources/CodexBar/Providers/Grok/UsageStore+GrokLocalSessions.swift)
  • Chipagosfinest: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@steipete

steipete commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Thank you for the Muse work. Closing this overlapping implementation in favor of #3340’s better-proven local-token approach. This patch retains cross-provider fallback, deleted-cache invalidation, history-coverage and append-I/O defects. One scanner/cache owner is preferable; useful independent improvements can be incorporated with your credit.

@steipete steipete closed this Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants