Instruction manual

timharris707/modeldeck instruction manual

Source-visible macOS 14+ menu bar application with a bundled localhost Node daemon that monitors remaining Claude Code and Codex CLI rate-limit windows across isolated accounts, alerts on low capacity, and switches the account used by new CLI sessions without acting as a Claude Code plugin.

1. What ModelDeck is and how it relates to Claude Code

ModelDeck is a macOS 14+ menu-bar application for monitoring Claude Code and Codex CLI usage across multiple accounts. It shows the percentage remaining in each rate-limit window, reset times in your local time zone, plan labels, and model-specific weekly limits. It can also warn when capacity becomes low and activate a different account for future terminal sessions.

**Classification:** standalone companion application that **runs alongside** Claude Code. Its documented mechanism is a native SwiftUI desktop interface backed by a localhost Node.js daemon. It is not documented as a Claude Code plugin, skill, hook, MCP server, or context-injection package. It relates to Claude Code by reading usage and authentication state through existing provider-managed profiles and by switching isolated `CLAUDE_CONFIG_DIR` homes for new sessions. Codex support works similarly through separate `CODEX_HOME` directories and the official `codex app-server` protocol.

ModelDeck does not replace either CLI. You must already have the Claude Code and/or Codex CLI you want to track. Each provider has one account considered active for **new** sessions; changing it does not stop, log out, or modify an already-running session. Activation is verified and reported as `effective`, `identity-mismatch`, or `identity-unverified`, rather than being assumed successful.

The product is source-visible and licensed under PolyForm Noncommercial 1.0.0 for personal, noncommercial reading, building, running, and sharing. The README says commercial rights are reserved and directs prospective commercial users to open an issue.

2. Requirements, released-app installation, and first launch

For the released application, you need macOS 14 or later and at least one supported provider CLI: Claude Code, Codex CLI, or both. Node.js is not required for the self-contained DMG; Node.js 24+ is required only when building or running the daemon from source.

  1. Open the repository’s public [Releases page](https://github.com/timharris707/modeldeck/releases).
  2. Download the latest signed and notarized DMG.
  3. Open the DMG and drag ModelDeck into Applications.
  4. Launch ModelDeck.

On first launch, the app asks permission to register its bundled background service. This service is the local daemon that performs usage reads. It listens only on `127.0.0.1:3867`. First launch also creates ModelDeck’s local Keychain authorization token. The documented DMG flow needs one approval and no Terminal work.

To add an account, open **Settings → Accounts → Add Account**. The guided process has three stages: assign a local label such as “Work” or “Personal,” sign in using the provider’s own browser-based login, and confirm the identity that ModelDeck reads back. Repeat the flow for every account you want represented in the deck.

Every added account receives an isolated, owner-only profile home. Claude profiles use `CLAUDE_CONFIG_DIR`; Codex profiles use `CODEX_HOME`. This separation is intended to prevent identities from bleeding into one another. If two profiles nevertheless share the same credential, ModelDeck displays a duplicate-token marker and warning banner instead of presenting them as independent usage pools.

3. Reading the usage deck and organizing accounts

Open the menu-bar item to see one card per configured account. A card’s headline meter represents that account’s worst remaining window—the limit closest to exhaustion. Expand the card to inspect every available rate-limit window, including session, weekly, and model-scoped weekly limits such as “Weekly · Fable.” Each detail row shows the percentage remaining and a right-aligned reset time converted to your time zone.

Claude Code and Codex accounts can appear in side-by-side provider columns. A single-column layout is also available. The documented sort choices are next reset, lowest remaining, and provider. Use lowest remaining when you want the most constrained account surfaced first; use next reset when reset timing is the priority.

The menu-bar icon summarizes capacity without opening the deck. It remains a plain glyph while tracked capacity is healthy, adds a gold percentage when an account is below the configured low threshold, turns red at the critical level, and returns to plain after recovery. You can instead pin one named account or “the active account,” either in Settings or from a card’s right-click menu, so that account’s percentage remains visible continuously.

Cards also show provider plan information, such as “Pro” or “Max (20x),” where available. CLI health reports installed versus latest Claude Code and Codex CLI versions, while per-account authentication chips report states such as **Healthy** or **Sign in again**. Reads used by the app—health, state, settings, and cached tool information—use daemon caches and do not themselves initiate provider polling.

4. Alerts, account activation, settings, dashboard, and updates

Configure the remaining-percentage threshold in Settings. ModelDeck posts a macOS notification only when an account’s worst remaining percentage crosses the configured threshold or reaches critical status. It does not repeatedly notify while the account stays below the boundary. Recovery re-arms the alert for a later crossing. Notification permission is requested only when needed.

Use **Activate** on an account when you want that identity selected for newly opened CLI sessions. Activation atomically swaps the relevant isolated profile home, verifies the resulting identity, and exposes the verification state. Existing Claude Code or Codex processes keep their current account and are not interrupted.

General settings cover deck layout and sorting, refresh cadence, threshold behavior, menu-bar display, launch at login, and update controls. Settings are stored by the daemon, loaded when the app starts, and applied live. Launch at login uses the assembled app bundle; it does not work from a bare `swift run` process.

ModelDeck’s only browser page is a read-only usage dashboard at `/dashboard`. It is served by the same loopback daemon and is available only when the `usageAnalyticsEnabled` setting is enabled; open it from the native app. The retired control-plane web UI is not part of current operation.

Update checks are off until you enable them. When enabled, ModelDeck may check the repository’s public release feed daily. **Update Now** downloads an approved release, verifies its EdDSA and Apple signatures, installs it, and relaunches. Once checks are enabled, automatic installation is on by default and installs quietly on the next relaunch. Turning checks off disables ModelDeck’s own update traffic.

5. Privacy, credentials, local service, and data boundaries

ModelDeck documents no cloud backend, synchronization account, or telemetry. The daemon binds to loopback rather than an external network interface. Its normal provider traffic goes only to the providers already used by your CLIs, using credentials those provider-managed profiles already contain. Claude usage is read through Anthropic’s native usage endpoint; Codex usage is read through the official app-server stdio protocol.

ModelDeck does not initiate provider logins, refresh provider tokens, copy provider credentials into its own database, or persist those credentials. Sign-in remains the provider’s browser flow, and provider secrets remain in the provider-managed profile or macOS Keychain. Removing a ModelDeck account deletes ModelDeck’s reference, not the provider’s authentication state.

ModelDeck does create its own local secrets. One random Keychain token authorizes the native app to the daemon. If the managed proxy is used, it also creates one local client key per profile under a service name shaped like `cli-proxy-api-client.<profile>`. The README states that these items contain no provider data.

The daemon stores state in an owner-only SQLite database under `~/Library/Application Support/ModelDeck/` by default. Its HTTP API rejects unexpected Host and Origin headers. Mutating requests obtain a session token and return it in both the `x-modeldeck-token` header and a `SameSite=Strict` `modeldeck_session` cookie.

The only optional outbound calls attributed to ModelDeck itself are the enabled daily release-feed check and a release download you approve or permit through automatic updates. Provider usage reads are separate and necessarily contact the configured providers.

6. Uninstalling while preserving or deleting local state

Uninstalling does not touch `~/.claude`, `~/.codex`, or provider credentials. Those remain owned by the CLIs and their login flows.

For a DMG installation, quit from the menu-bar icon’s right-click menu, then drag ModelDeck from Applications to the Trash. The background service and launch-at-login entry are inside the app bundle, so removing the bundle removes them without Terminal commands.

To preserve account setup and history for a reinstall, stop there. To delete ModelDeck’s data too, remove `~/Library/Application Support/ModelDeck`, which contains settings, usage history, and ModelDeck-created isolated profile homes. Deleting it removes those managed sign-ins but not your separate `~/.claude` or `~/.codex` homes. If the daemon was configured with `MODELDECK_DATA_DIR` or `MODELDECK_DB_PATH`, delete the configured location instead. Optional residual paths are `~/Library/Preferences/app.modeldeck.mac.plist`, `~/Library/Caches/app.modeldeck.mac`, and `~/Library/LaunchAgents/ai.hermes.modeldeck.plist` if the source launch agent was used.

For an existing Homebrew installation, the documented commands are:

brew uninstall modeldeck

This preserves data. To remove app data as well:

brew uninstall --zap modeldeck

Keychain items survive both Trash and `--zap`. Delete them in Keychain Access by searching for `modeldeck` and `cli-proxy-api-client`, or remove the daemon token with:

security delete-generic-password -s modeldeck -a mutation-token

For each managed-proxy profile, substitute its real profile name here:

security delete-generic-password -s "cli-proxy-api-client.<profile>" -a ""

7. Building, running, and testing from source

Source development requires Node.js 24+; `package.json` specifies Node.js 24.16.0 or newer. From the repository root, install daemon dependencies and start the foreground service:

npm install
npm start

The daemon listens on `127.0.0.1:3867`. In another shell, run the native SwiftPM application:

cd macos/ModelDeckMac
swift run ModelDeckMac

A bare `swift run` build can use the daemon and UI, but launch-at-login and macOS usage notifications require an assembled `.app` bundle. Build that bundle from the repository root with:

macos/ModelDeckMac/Scripts/build_app.sh

The script assembles and signs `dist/ModelDeck.app`, using ad-hoc signing by default. From `macos/ModelDeckMac`, the package documentation also supports:

swift build
swift test
Scripts/build_app.sh

Run the daemon test suite from the repository root:

npm test

Run the app test suite with:

cd macos/ModelDeckMac && swift test

The Swift core tests cover thresholds, worst-percentage computation, API decoding, settings synchronization, notification transitions, and view models. The Node test command also detects when the committed dashboard artifact is older than its sources.

The package manifest declares additional maintenance scripts for watch-mode development, coverage, migrations, ingestion, demo seeding, scans, status, release checks, and compatibility checks. The supplied user-facing documentation does not define their operating procedures or safe inputs, so they are intentionally not recommended here as end-user commands.

8. Launch agent, dashboard development, architecture, and contribution guidance

To keep a checkout’s daemon running across logins instead of using the bundled service, run the documented launch-agent setup from the repository root:

scripts/set-mutation-token.sh
scripts/install-launch-agent.sh --port 3867

The first command performs one-time Keychain token setup; the second installs and starts a launchd agent on port 3867. The app normally uses `http://127.0.0.1:3867`. Developers may override the port with the `MODELDECK_PORT` environment variable or the `modeldeck.daemon.port` user default.

The dashboard source is a React application in `dashboard/`. Its production result is a single self-contained HTML artifact committed as `src/dashboard-app.mjs`, which the daemon and single-file binary can serve. After editing dashboard sources, regenerate the artifact with:

npm run dashboard:build

For Vite hot-module development against a daemon already running on port 3867, use:

npm run dashboard:dev

The native app is a SwiftPM `MenuBarExtra` client. `Sources/ModelDeckMacCore` contains typed API models, localhost client logic, usage evaluation, settings and account view models, notification transitions, tool status, and launch-at-login support. `Sources/ModelDeckMac` contains the menu-bar shell, deck popover, activation controls, Settings panes, visual status rendering, and notification posting. The Node daemon is API-only except for the optional read-only dashboard.

Issues and pull requests are welcome under the repository’s license. Useful bug reports include `/api/health` output plus macOS and CLI versions. Remove or replace real identities and usage figures before posting; the repository explicitly requests placeholder labels. Release construction is documented separately in `docs/RELEASE.md` and should not be improvised from the limited commands in this manual.