Skip to content

a native macOS app for tokenmaxx, with a menu bar item - #31

Open
pedroapfilho wants to merge 1 commit into
RubricLab:mainfrom
pedroapfilho:gui-app
Open

pedroapfilho wants to merge 1 commit into
RubricLab:mainfrom
pedroapfilho:gui-app

Conversation

@pedroapfilho

@pedroapfilho pedroapfilho commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

This is a proposal, so tell me whether it's worth doing. It adds a native macOS app for tokenmaxx, built with GPUI (Zed's UI framework) and the GPUI Kit components. The app does everything the terminal dashboard does, and it can also sit in the menu bar.

It's a large diff (+22k lines), but about 19k of that is gui/Cargo.lock and the JSON test fixtures. The real changes are the daemon changes below and the Rust app in gui/.

What the app does

  • Accounts: accounts are listed per provider, fullest first, with usage bars, reset countdowns, plan, and health. The active account is marked.
    • Each row has a Use button. A … menu holds the rest: sign in again, spend a Codex reset credit, spill into extra usage at the threshold, and sign out.
    • "Add account" either signs in with a subscription in your terminal, or takes an API key.
  • Analytics: a throughput chart and a pricing breakdown by provider, cost type, and model, over 1h / 5h / 24h / 7d / 31d.
  • Settings:
    • Per provider: routing, auto-switch, switch threshold, cooldown, and which limits to show.
    • Routing for pi.
    • Appearance: auto, light, or dark. Auto follows macOS and changes live.
    • Show tokenmaxx in: menu bar and Dock, menu bar only, or Dock only. It changes live.
    • The terminal used for sign-in: Ghostty, iTerm, WezTerm, kitty, Alacritty, or Terminal.
    • A command-line tool status, covered below.
  • Menu bar item: an icon only. Its menu lists each provider's accounts with their 5h and 7d usage, and clicking one switches to it. It also shows tokens per hour and the last 24h value, plus Refresh, Open, Settings, and Quit.

How it fits with the CLI

The daemon stays the one source of truth. The app is a thin client of the same unix socket (manager.sock) and the same ~/.tokenmaxx state.

  • Standalone app. tokenmaxx.app contains a bun build --compile copy of the CLI, so it works without Bun or npm installed.
  • One version drives the daemon. If a tokenmaxx on the user's PATH is at least as new as the app's copy, the app starts the daemon and runs sign-in through that one. Otherwise it uses its own copy, and Settings offers an Update button, which runs bun add -g tokenmaxx@<version> or the npm equivalent. It also offers to put the bundled copy on the PATH. The app never replaces a daemon newer than the version it would start.
  • Sign-in stays in a terminal. Subscription sign-in needs a terminal (a TTY), so the app opens the user's terminal running tokenmaxx login <cli> and picks up the new account on its next poll.

Changes to the existing TypeScript

  • New daemon methods: routing/read, routing/set (codex, claude, pi), account/addApiKey, and version/latest. The routing logic moved out of cli.ts into src/routing.ts.
  • CLI and dashboard use them. The CLI and the TUI now make these changes through the daemon, and the TUI no longer returns a routing action to the CLI.
  • --compile support. The daemon now starts correctly from a compiled binary; Bun.main is under /$bunfs/ there. A new compiledBinary flag makes the update hints point to the app instead of bun add -g.
  • tokenmaxx --version. New; the app uses it to compare versions.
  • daemon start now replaces a running daemon of a different version, the same way the other commands already do.
  • Bug fix in healInstalledConfigs. It used to re-apply routing to every routed config using the starting daemon's own port. A daemon started with a different TOKENMAXX_HOME and TOKENMAXX_PROXY_PORT would then point the user's real codex and claude configs at itself. It now only rewrites configs already routed to its own port. A regression test covers this.

Trying it

bun run gui:dev     # compiles the CLI, then runs the app against it
bun run gui:bundle  # gui/target/tokenmaxx.app (ad-hoc signed)

This needs Rust stable and Xcode's command-line tools. gui/ isn't part of CI; the existing workflow still runs only on Ubuntu.

When testing, isolate the client configs as well: CODEX_HOME, CLAUDE_CONFIG_DIR, and PI_CODING_AGENT_DIR, not only TOKENMAXX_HOME. Otherwise a routing toggle changes your real configs.

Tested

  • bun run check: 93 tests pass, including the new daemon-method tests and the heal regression test.
  • cargo test: 12 tests pass, covering the formatting ported from tui/format.ts, the app parsing every TUI fixture, the menu command ids, and version ordering.
  • The dev app and the bundled .app against a test daemon:
    • An auto-switch toggle showed up in tokenmaxx status.
    • Light and dark switched live.
    • Menu bar only mode removed the Dock icon live.
    • The status item existed.

Not tested yet:

  • The menu bar menu's contents and switching from it.
  • Terminal sign-in, adding an API key, sign-out, reset credits, and the command-line tool install and update.
  • Rows with real accounts.
  • Dock only mode, and closing then reopening the window.

Open questions

  1. Do we want this at all? It's a second UI in Rust on top of a TypeScript daemon.
  2. Distribution. Anyone else can only get the app by building it from source. Shipping it properly needs a macOS CI job that builds, signs with a Developer ID, and notarizes a .dmg/.zip for GitHub Releases, plus a Homebrew cask. That needs a Rubric Labs Apple Developer account.
  3. gpui-kit pins a weekly GPUI snapshot (gpui-pre =0.3.6), so expect small API changes whenever we bump it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant