{"id":51331030,"url":"https://github.com/livin21/pitstop","last_synced_at":"2026-07-01T23:01:45.659Z","repository":{"id":364328146,"uuid":"1267428350","full_name":"Livin21/pitstop","owner":"Livin21","description":"macOS menu bar app that tracks usage limits and switches accounts across Claude Code, Claude Desktop, and OpenAI Codex — one click to flip when one hits its rate limit.","archived":false,"fork":false,"pushed_at":"2026-07-01T15:27:39.000Z","size":1775,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-07-01T17:23:38.118Z","etag":null,"topics":["anthropic","claude","claude-code","claude-desktop","codex","developer-tools","macos","menubar-app","openai","swift"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Livin21.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-12T14:30:09.000Z","updated_at":"2026-07-01T15:27:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Livin21/pitstop","commit_stats":null,"previous_names":["livin21/pitstop"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Livin21/pitstop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Livin21%2Fpitstop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Livin21%2Fpitstop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Livin21%2Fpitstop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Livin21%2Fpitstop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Livin21","download_url":"https://codeload.github.com/Livin21/pitstop/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Livin21%2Fpitstop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35025983,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","claude","claude-code","claude-desktop","codex","developer-tools","macos","menubar-app","openai","swift"],"created_at":"2026-07-01T23:01:34.652Z","updated_at":"2026-07-01T23:01:45.653Z","avatar_url":"https://github.com/Livin21.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/icon.png\" width=\"128\" alt=\"PitStop icon\"\u003e\n\u003c/p\u003e\n\n# PitStop\n\nmacOS menu bar app that tracks **usage limits** across your AI coding accounts\n— **Claude Code**, **Claude Desktop**, and **OpenAI Codex** — and lets you\n**switch accounts** with one click, so when one hits its rate limit you flip to\nanother and your work keeps going.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/menu.png\" width=\"465\" alt=\"PitStop menu grouped into Claude and Codex sections, each with color-coded usage bars\"\u003e\n\u003c/p\u003e\n\nAccounts are grouped into a section per provider — **Claude**, **Codex**, and\nwhatever comes next. Within each section the live account is marked with a\ncoral dot and listed first, then the rest by headroom (emptiest next — the one\nyou'd switch to). Hovering a switchable row flips its plan chip into a coral\n**Switch** pill. A small tag on each row names the surface — **Code**,\n**Desktop**, or **Code · Desktop** — so you can tell a switchable CLI account\nfrom a read-only Desktop one at a glance. The menu bar shows the active Claude\nCode account's binding limit, color-coded.\n\nWhat shows up where:\n\n- **Claude Code** accounts are switchable. **Claude Desktop** (a *different*\n  login) shows read-only, tagged **Desktop**; an account signed into both Code\n  and Desktop is one shared usage pool, so it stays a single row tagged\n  **Code · Desktop**.\n- **OpenAI Codex** accounts are switchable too — its login lives in\n  `~/.codex/auth.json` (shared by the Codex CLI and the Codex app), which\n  PitStop snapshots per account and swaps the same way it swaps the Claude\n  Code credential. Each plan's rate-limit windows render as bars just like\n  Claude's 5-hour and weekly limits.\n\n## Quickstart\n\nUsing an AI agent? Copy this prompt into Claude Code (or any agent that can\nrun shell commands) on the target Mac:\n\n```text\nInstall and set up PitStop (https://github.com/Livin21/pitstop), a macOS\nmenu bar app that tracks usage limits and switches accounts across Claude\nCode, Claude Desktop, and OpenAI Codex, on this Mac.\n\n1. Verify requirements: macOS 26+, Xcode Command Line Tools\n   (xcode-select --install), and Claude Code installed and logged in.\n   Stop and tell me if any are missing.\n2. Clone the repo and run ./scripts/make-app.sh — it builds and installs\n   /Applications/PitStop.app. Then `open /Applications/PitStop.app`.\n3. You cannot interact with macOS security dialogs — walk me through\n   them instead: when PitStop first reads the Claude Code credentials,\n   macOS may ask for my login keychain password. I'll enter it and click\n   \"Always Allow\" (plain \"Allow\" makes the prompt come back). The grant\n   is one-time; it survives rebuilds. If I use the Claude Desktop app too,\n   a second identical prompt may appear for \"Claude Safe Storage\" (so\n   PitStop can show that account's usage) — same deal, Always Allow.\n4. Verify: a checkered-flag icon appears in the menu bar showing my\n   usage percentage, and `.build/release/PitStop --check` prints my\n   account with live usage numbers.\n5. Tell me how to add a second account: run /login in Claude Code and\n   sign in with the other account — PitStop saves it within 2 minutes\n   (or via \"Save Current Account\" in the menu). I'll also click \"Allow\"\n   on the notification prompt the first time it warns about usage.\n6. If I also use OpenAI Codex or the Claude Desktop app, tell me they're\n   detected automatically and show up in their own menu sections — Codex\n   accounts are switchable like Claude Code (it reads ~/.codex/auth.json,\n   no keychain grant), Claude Desktop is read-only.\n```\n\nOr set it up manually:\n\n1. Requirements: **macOS 26+**, Xcode Command Line Tools, and Claude Code\n   logged in at least once.\n2. Build and install:\n   ```sh\n   git clone https://github.com/Livin21/pitstop \u0026\u0026 cd pitstop\n   ./scripts/make-app.sh\n   open /Applications/PitStop.app\n   ```\n3. When macOS asks for your login keychain password, enter it and click\n   **Always Allow** — one-time; see [Caveats](#caveats).\n4. Add more accounts per [Adding a second account](#adding-a-second-account).\n\n## How it works\n\n- **Usage** comes from Anthropic's OAuth usage endpoint\n  (`api.anthropic.com/api/oauth/usage`), called with the same OAuth token\n  Claude Code uses. Refreshes every 2 min (debounced on menu open), with\n  exponential backoff honoring `Retry-After` when Anthropic rate-limits,\n  retrying as soon as the backoff window expires; the last good numbers\n  stay visible (rows note \"showing … data\"; the menu bar dims) during\n  outages.\n- **Menu bar number** is, by default, the active Claude Code account's\n  binding constraint — `max(5-hour, weekly)` utilization — with a warning dot\n  from 75 % (🟠) and 90 % (🔴). (Dots rather than colored text: macOS repaints\n  menu bar items in a single wallpaper-matched ink, and emoji are the only\n  glyphs that keep their color.) **Settings** customizes it: what it shows\n  (icon \u0026 percent / icon only / percent only), which account it tracks (the\n  active Claude Code account, or the most-used account across any provider),\n  and which limit drives the number (highest / 5-hour / weekly).\n- **Auto-switch** (off by default) flips a switchable provider's live account\n  — Claude Code or Codex — to the saved account with the most headroom once\n  the live one crosses a configurable threshold, and notifies you. It only\n  moves onto accounts with trustworthy fresh data, and a per-provider cooldown\n  prevents flapping; Desktop is read-only and left alone.\n- **Time-to-limit projection** (on by default) samples usage over time and,\n  when a window is trending toward full *before* it resets, shows\n  \"↗ on pace to hit limit ~3:40 PM\" on the row.\n- **Notifications** fire when the active account crosses 80 % and 95 %,\n  with the reset time, so you can switch before sessions stall.\n- **Settings** (⌘, from the menu) is a small window holding all preferences —\n  the menu-bar options above, auto-switch, the projection toggle, and launch\n  at login.\n- **Accounts** are snapshots of the Claude Code credential blob:\n  - secrets live in the **keychain** (service `PitStop-profile`, one item\n    per account email) — never written to disk;\n  - non-secret identity (email, org, plan) lives in\n    `~/.config/pitstop/profiles.json`.\n- **Claude Desktop** (the chat app) is read separately and read-only. It\n  signs into claude.ai with a cookie session rather than the OAuth token\n  Claude Code uses, so PitStop decrypts that app's `sessionKey` cookie\n  (Chromium AES, keyed by the `Claude Safe Storage` keychain item, read\n  through the same `security` path) and calls claude.ai's usage endpoint —\n  which happens to return the same shape as the OAuth one. PitStop never\n  writes to Claude Desktop's data; you can't switch a Desktop account from\n  PitStop (its login lives in that app).\n- **OpenAI Codex** uses `~/.codex/auth.json` — the ChatGPT OAuth token the\n  Codex CLI and Codex app both use — for both identity and switching. Usage\n  comes from `chatgpt.com/backend-api/codex/usage`, a cheap metadata call\n  returning each rate-limit window's used-percent and reset time. Switching is\n  the file analog of the Claude flow: PitStop snapshots the live `auth.json`\n  per account into the keychain (service `PitStop-codex`) and, on switch,\n  writes the chosen account's snapshot back into the file (compacted — JSON is\n  whitespace-insensitive, and `security` mangles multi-line secrets). Inactive\n  snapshots whose access token has aged out are refreshed via the ChatGPT\n  OAuth refresh grant (against Codex's public client) and the rotated tokens\n  stored back, so an inactive account shows live usage and a switch into it\n  lands a fresh token — the *live* account is left to Codex, which keeps it\n  fresh itself. The CLI and app share one login, so each Codex account is one\n  row. Per-account state is keyed by provider, so a Claude account and a Codex\n  account that happen to share an email stay distinct rows.\n- **All keychain access goes through `/usr/bin/security`** — the same CLI\n  Claude Code shells out to. One \"Always Allow\" grant (enter the keychain\n  password when prompted) covers both apps and survives PitStop rebuilds,\n  since the requester is the stable Apple-signed `security` binary rather\n  than the re-signed app bundle. Trade-off: writes pass the blob via argv\n  (briefly visible in the process list) — same exposure Claude Code has.\n- **Switching a Claude account** writes its blob back into the live\n  `Claude Code-credentials` keychain item and restores its `oauthAccount`\n  identity in `~/.claude.json`. The whole blob is swapped, so per-account MCP\n  OAuth tokens (e.g. Atlassian) move with it. (Codex switching is the file\n  analog — see the Codex bullet above.)\n- **Stale tokens** of saved (inactive) Claude accounts are refreshed\n  automatically via the standard OAuth refresh grant against Claude Code's\n  public client, and the refreshed tokens are stored back. The *active*\n  account is never refreshed by PitStop — Claude Code keeps it fresh itself\n  (PitStop only steps in as a fallback if it finds the live token already\n  expired).\n\n## Adding a second account\n\nPitStop can only switch between accounts it has snapshotted, and it snapshots\nwhatever is *live* on each refresh — so seed each account by being logged into\nit once while PitStop runs:\n\n1. PitStop auto-saves whatever account is currently live.\n2. Sign in with the **other** account — Claude Code: run `/login`; Codex: run\n   `codex` and sign in (the CLI and the Codex app share this login).\n3. PitStop notices it on the next refresh and saves it too (for Claude you can\n   also click **Save Current Account**).\n4. Both accounts now appear in the menu — click either to switch.\n\n## What switching means for running sessions\n\nAfter a switch, the live credential (Claude Code's keychain item, or Codex's\n`~/.codex/auth.json`) points at the new account:\n\n- **New sessions** use the new account immediately.\n- **Running Claude Code sessions** keep working on the old in-memory token\n  until it expires (tokens are short-lived), then re-read the keychain — no\n  restarts.\n- **The Codex app**, if open, may need a quit-and-reopen to pick up the swap\n  (and can overwrite `auth.json` from memory while running — switch Codex with\n  the app closed for a clean result).\n\n## Development\n\n`./scripts/make-app.sh` builds release and installs\n`/Applications/PitStop.app`. Useful flags on the bare binary:\n\n- `--check` — print accounts and live usage to stdout, no GUI.\n- `--preview` — render sample account rows to `/tmp/pitstop-preview.png`\n  for iterating on the row design.\n- `--screenshot` — run the app with sample addresses in place of real\n  emails, for README captures.\n\nThe app icon (usage gauge with a coral needle nearing the red zone, over a\ncheckered pit-lane strip) is drawn programmatically — regenerate\n`Resources/AppIcon.icns` after design tweaks with:\n\n```sh\nswift scripts/make-icon.swift\n```\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for release history (also published on\n[GitHub Releases](https://github.com/Livin21/pitstop/releases)).\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for build\nsteps, style, and how to add a provider. Please open an issue before anything\nnon-trivial. Because PitStop handles live credentials, report security issues\n**privately** per the [security policy](SECURITY.md), not as a public issue. By\nparticipating you agree to the [Code of Conduct](CODE_OF_CONDUCT.md).\n\n### Caveats\n\n- Keychain prompts are **one-time per item**: when `security` first touches\n  an item it isn't yet allowed on, macOS asks for the login keychain\n  password — enter it and click **Always Allow** (plain \"Allow\" grants once\n  and the prompt returns). Because access rides the Apple-signed `security`\n  CLI, rebuilds of PitStop do **not** re-trigger prompts.\n- `~/.claude.json` is rewritten on switch (only the `oauthAccount` key is\n  changed, but the file is re-serialized). Claude Code rewrites this file\n  constantly itself; a concurrent write race is theoretically possible but\n  the window is milliseconds.\n- **Claude Desktop** support adds one more one-time keychain grant: the first\n  time PitStop reads the `Claude Safe Storage` item (to decrypt that app's\n  session cookie), macOS prompts — enter the password and click **Always\n  Allow**, same as the credentials grant. It reads claude.ai's unofficial web\n  endpoints with the desktop app's own session; if those change, update\n  `ClaudeDesktop.swift`. If Claude Desktop isn't installed or isn't signed\n  in, nothing changes.\n- **Codex** keeps inactive snapshots fresh via the OAuth refresh grant, but\n  the *live* account is Codex's to maintain — PitStop never rewrites the live\n  `auth.json` on a refresh cycle. So if the live account's token is expired\n  (e.g. right after switching into an account whose snapshot was stale), its\n  row says \"run codex to refresh\" — running `codex` (or any use) refreshes it.\n  An inactive account only shows \"sign in to Codex again\" if its refresh token\n  is itself dead. Reading `auth.json` needs no keychain prompt (it's a plain\n  file); saving/refreshing snapshots creates `PitStop-codex` keychain items the\n  same silent way as the Claude ones. It reads ChatGPT's unofficial backend and\n  OAuth endpoints; if those change, update `Codex.swift`. Not installed or not\n  signed in → nothing changes.\n- The usage endpoint and refresh flow are the same unofficial OAuth surface\n  Claude Code itself uses; if Anthropic changes them, update `UsageAPI.swift`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivin21%2Fpitstop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flivin21%2Fpitstop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivin21%2Fpitstop/lists"}