You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Provide a small native macOS menu-bar client that consumes tokemon's versioned status document without reimplementing parsing, pricing, or aggregation.
Phased scope
Phase 1: local alpha
Add a native menu-bar item with a compact popover.
Launch the installed tokemon binary and poll tokemon status --json on a configurable interval.
Show one headline metric (tokens, cost, or combined) and Today, This Week, This Month, and All Time scopes.
Provide manual refresh, last-refresh time, an action to open the terminal dashboard, and quit.
Keep all parsing and pricing in tokemon; the client only decodes the versioned status document.
Phase 2: polish
Add configurable binary path, metric, scope, and refresh interval.
Distinguish missing binary, incompatible schema, empty history, and source/cache failures.
Document local build, installation, and upgrade steps.
Safety boundaries
macOS only for the first alpha; no cross-platform client in this issue.
No daemon, IPC service, telemetry, account access, network calls, or provider credentials.
Refreshing must never block the menu-bar UI.
Acceptance criteria
The applet runs in the macOS menu bar without a normal Dock window.
Polling consumes only the versioned status command and never duplicates core logic.
Headline metric, scope, and refresh interval are configurable.
Empty, unavailable, incompatible, and failed states are visibly distinct.
The applet has a documented local build/install path and automated contract-fixture coverage.
This issue is now scoped as a local-only, macOS-only menu-bar client of the existing versioned status command. The applet must not duplicate source parsing, pricing, aggregation, or discovery.
Contract hardening
Keep schema_version: 1 as the applet contract.
Report pricing availability explicitly; a zero cost must not be used to mean "pricing unavailable".
Add fixtures for populated, empty, malformed, future-schema, unknown-field, pricing-available, and pricing-unavailable responses.
Preserve compatibility by allowing unknown response fields.
Process runner
Invoke the configured binary directly, never through a shell.
Always pass status --json --offline so the applet cannot trigger network pricing.
Capture stdout and stderr separately.
Enforce a five-second timeout and a bounded output size.
Run refreshes off the UI thread, allow only one active refresh, and preserve the last successful result when a refresh fails.
Resolve an explicitly configured executable first, then fall back to the process path.
Scopes and metrics
Scopes: today, current ISO week, current month, and all time.
Use the CLI's existing UTC date semantics for the first version; do not introduce local-calendar drift in the applet.
Metrics: tokens, cost, and combined.
If pricing is unavailable, show an explicit unavailable state rather than $0.
Menu-bar UI
Run without a normal Dock window.
Show the selected headline metric, scope, provider count, last refresh time, loading state, stale state, and actionable errors.
Provide refresh, metric selection, scope selection, preferences, dashboard launch, and quit actions.
Dashboard launch must also avoid shell interpolation and must not block the UI.
Preferences
Persist locally:
Binary path
Metric
Scope
Refresh interval
Use safe defaults, validate paths and intervals, and fall back cleanly from invalid preferences. Launch-at-login, notifications, accounts, credentials, and cloud sync are out of scope.
Error states
Present distinct states for missing executable, non-executable path, timeout, non-zero exit, invalid JSON, unsupported schema, missing fields, empty history, unavailable pricing, and stale data after a failed refresh.
Tests and CI
Add contract decoder, process-runner, refresh-state, preference, and metric/scope tests.
Add macOS build and native test coverage without signing or notarization secrets on pull requests.
Keep the existing Rust Linux/macOS/Windows CI intact.
Add manual QA cases for empty data, populated data, missing binary, timeout, malformed output, unsupported schema, and offline pricing.
Documentation and packaging
Document local macOS build, installation, removal, configuration, troubleshooting, UTC scope semantics, and offline pricing behavior.
Keep the first milestone local-build only; signed/notarized distribution and release artifacts are a follow-up.
Keep the native target separate from the cross-platform Rust CLI.
Decisions fixed for this implementation
Local-only alpha
macOS-only target
UTC period boundaries to match the existing CLI
60-second default refresh, five-second minimum, five-second process timeout
No daemon, telemetry, network access, credentials, raw-log parsing, or duplicated core logic
Definition of done
The applet is complete when it remains responsive during refresh, consumes only the offline versioned status interface, supports all four scopes and three metrics, persists and validates its preferences, distinguishes all required failure states, passes contract/process/model/macOS tests, and has documented local installation and removal steps.
The scoped Phase 1 implementation is now complete in draft PR #43.
Delivered in incremental commits:
Hardened the status contract so capabilities.cost reflects actual pricing availability, including offline/no-price cases.
Added the macOS 13+ Swift package and accessory menu-bar executable.
Added a direct process runner for status --json --offline with separate stdout/stderr capture, five-second timeout, bounded output, and launch/non-zero/encoding/schema errors.
Added UTC today, ISO-week, month, and all-time queries.
Added persisted executable-path, metric, scope, and refresh-interval preferences with safe defaults and validation.
Added background refreshes that do not block the UI, preserve the last successful report after a failure, and distinguish missing/non-executable paths, empty history, unavailable pricing, malformed output, and unsupported schemas.
Added headline tokens/cost/combined metrics, provider count, refresh time, manual refresh, dashboard launch, preferences, and quit actions.
Added contract, runner, query, preference, stale-state, and metric tests, plus a macOS CI job.
Documented local build, user-local installation/removal, configuration, scope semantics, offline pricing, and troubleshooting.
cargo clippy -- -W clippy::pedantic -A clippy::module_name_repetitions
cargo build --release
swift test (21 tests)
swift build -c release
GitHub CI: format, clippy, Linux/macOS/Windows Rust tests, and macOS menu-bar tests
The PR remains draft for review. Signing, notarization, packaging, launch-at-login, notifications, provider toggles, and distribution are intentionally follow-up work outside this local alpha.
Phase 1 is merged in PR #43. I’m taking the next bounded, non-release polish slice from the remaining issue scope: persisted provider filters for the menu-bar client.
Scope
Persist an optional provider allow-list with the existing local preferences.
Expose it as a comma-separated field in Preferences…; blank means all providers.
Normalize whitespace, remove empty names, and de-duplicate entries before saving or invoking the CLI.
Pass each selected provider as a repeatable --provider argument to status --json --offline.
Keep filtering in the existing Rust status command; the macOS client will not parse or filter raw usage data.
Preserve the last successful report and existing error behavior when a filtered refresh fails.
Acceptance criteria
Existing users load with no provider filter and retain current behavior.
A saved filter round-trips through UserDefaults in stable order.
Status queries contain one repeatable provider argument per normalized selection.
The UI documents that blank means all providers and never enables network access.
Unit tests cover normalization, persistence, argument construction, and refresh propagation.
Packaging, signing, distribution, launch-at-login, notifications, and budget alerts remain separate follow-up slices.
Provider-filter slice is implemented in draft PR #44: https://github.com/mm65x/tokemon/pull/44\n\nThe PR persists an optional comma-separated allow-list, normalizes and de-duplicates entries, passes repeatable filters to offline status refreshes, preserves the existing last-successful-result behavior, and documents blank as all providers. Local and CI verification are green.
PR #44 has been merged into develop. The provider-filter slice is now integrated: persisted optional allow-list, normalization/de-duplication, repeatable offline status filters, tests, and documentation. Packaging/signing/distribution and budget notifications remain follow-up work.
Activity
mm65x commentedon Aug 11, 2026
Vetted implementation scope
This issue is now scoped as a local-only, macOS-only menu-bar client of the existing versioned status command. The applet must not duplicate source parsing, pricing, aggregation, or discovery.
Contract hardening
schema_version: 1as the applet contract.Process runner
status --json --offlineso the applet cannot trigger network pricing.Scopes and metrics
$0.Menu-bar UI
Preferences
Persist locally:
Use safe defaults, validate paths and intervals, and fall back cleanly from invalid preferences. Launch-at-login, notifications, accounts, credentials, and cloud sync are out of scope.
Error states
Present distinct states for missing executable, non-executable path, timeout, non-zero exit, invalid JSON, unsupported schema, missing fields, empty history, unavailable pricing, and stale data after a failed refresh.
Tests and CI
Documentation and packaging
Decisions fixed for this implementation
Definition of done
The applet is complete when it remains responsive during refresh, consumes only the offline versioned status interface, supports all four scopes and three metrics, persists and validates its preferences, distinguishes all required failure states, passes contract/process/model/macOS tests, and has documented local installation and removal steps.
mm65x commentedon Aug 11, 2026
Implementation progress
The scoped Phase 1 implementation is now complete in draft PR #43.
Delivered in incremental commits:
capabilities.costreflects actual pricing availability, including offline/no-price cases.status --json --offlinewith separate stdout/stderr capture, five-second timeout, bounded output, and launch/non-zero/encoding/schema errors.Verification is green locally and on PR #43:
cargo fmt -- --checkcargo testcargo clippy -- -W clippy::pedantic -A clippy::module_name_repetitionscargo build --releaseswift test(21 tests)swift build -c releaseThe PR remains draft for review. Signing, notarization, packaging, launch-at-login, notifications, provider toggles, and distribution are intentionally follow-up work outside this local alpha.
mm65x commentedon Aug 12, 2026
Phase 2 slice: provider filters
Phase 1 is merged in PR #43. I’m taking the next bounded, non-release polish slice from the remaining issue scope: persisted provider filters for the menu-bar client.
Scope
--providerargument tostatus --json --offline.Acceptance criteria
UserDefaultsin stable order.Packaging, signing, distribution, launch-at-login, notifications, and budget alerts remain separate follow-up slices.
mm65x commentedon Aug 12, 2026
Provider-filter slice is implemented in draft PR #44: https://github.com/mm65x/tokemon/pull/44\n\nThe PR persists an optional comma-separated allow-list, normalizes and de-duplicates entries, passes repeatable filters to offline status refreshes, preserves the existing last-successful-result behavior, and documents blank as all providers. Local and CI verification are green.
mm65x commentedon Aug 13, 2026
PR #44 has been merged into develop. The provider-filter slice is now integrated: persisted optional allow-list, normalization/de-duplication, repeatable offline status filters, tests, and documentation. Packaging/signing/distribution and budget notifications remain follow-up work.