If you're using OpenAI Codex seriously, you've probably hit this wall: you have
multiple accounts, each with its own 5-hour and weekly usage limits, and the only
way to know how much any of them has left is to log into each one individually and
run /status.
That gets old fast. Here's how I solved it with a small Python dashboard that shows every account's remaining limits on one page — no third-party apps, no keychain access, nothing leaving my machine.
The Problem
Codex Plus accounts come with two rolling usage windows: a 5-hour window that resets every 5 hours, and a weekly window that resets every 7 days. When you're rotating between accounts as each one hits its limit, you need to know at a glance which account has room. Logging into each one to check is exactly the kind of friction that sounds minor until you're doing it five times a day.
There's no official API for this — OpenAI doesn't expose a "check my Codex limits"
endpoint in their platform API. The usage data lives inside each account's OAuth
token, the same login your Codex CLI already stores locally at ~/.codex/auth.json.
That's the key insight the whole thing is built on.
How It Works
When you log into Codex, it saves a login token to ~/.codex/auth.json. That token
is all you need to ask OpenAI's backend how much usage is left on that account. The
script reads the file, makes one HTTPS call per account, and gets back the same
numbers /status shows you inside the app — no password, no keychain, no
third-party service. The token is sent only to chatgpt.com and never stored or
logged anywhere.
For multiple accounts, each login lives in its own isolated folder:
mkdir -p ~/.codex-acct1
CODEX_HOME=~/.codex-acct1 codex login
mkdir -p ~/.codex-acct2
CODEX_HOME=~/.codex-acct2 codex loginEach folder holds one account's login, completely independent of the others. The dashboard reads all of them.
The Dashboard
The whole thing is a single Python file, standard library only, no pip packages. It
spins up a tiny local web server on localhost:8788 and serves one page that shows
every account as a card — 5-hour remaining and weekly remaining, each color-coded
green/amber/red with a progress bar and a reset countdown, plus any emergency
limit-reset credits the account has left. The page refreshes itself every 60
seconds, with a manual Refresh button for an instant update. It binds to
127.0.0.1 only — nothing is exposed to the internet.
def fetch_one(auth_path):
_, access, _ = _load_auth(auth_path)
exp = _jwt_exp(access)
if exp and exp - time.time() < 90:
access = _refresh(auth_path) or access
try:
return _get_usage(access)
except urllib.error.HTTPError as e:
if e.code != 401:
raise
access = _refresh(auth_path)
return _get_usage(access)Keeping Logins Alive Automatically
The first version had a problem: if an account sat idle long enough, its short-lived access token would expire and the card would go stale, and I'd have to manually re-login to restore it.
The fix was to make the dashboard maintain its own logins. Each auth.json stores
both a short-lived access token and a long-lived refresh token. Before every usage
fetch, the script checks whether the access token is close to expiring and quietly
renews it using the refresh token — the same mechanism the Codex CLI uses
internally:
exp = _jwt_exp(access)
if exp and exp - time.time() < 90:
access = _refresh(auth_path)That means the dashboard's monitor logins stay alive on their own, completely separate from whatever accounts I'm actively working in. Set it up once and it handles itself.
The one thing it can't survive is a deliberate Log Out from the Codex app — that kills the refresh token everywhere, including the dashboard's copy. The fix is a one-line alias per account:
alias fixacct1='CODEX_HOME=~/.codex-acct1 codex login'
alias fixacct2='CODEX_HOME=~/.codex-acct2 codex login'Add these to ~/.zshrc, and restoring a dropped account is just typing fixacct1
in Terminal.
The Team Overview
Below the account cards, two more panels answer questions the cards can't: a "pool weekly capacity" donut showing the average weekly room left across all accounts, plus which account frees up soonest; and a 7-day timeline with a dot for each account on the day its weekly limit refills. Both update on the same 60-second cycle.
Making It Easy to Use
A script you have to launch from Terminal every day gets old, so a double-click
desktop launcher starts the server and opens the browser automatically. For
switching between accounts day-to-day, short aliases beat typing the full
CODEX_HOME command every time:
alias codex1='CODEX_HOME=~/.codex-acct1 codex'
alias codex2='CODEX_HOME=~/.codex-acct2 codex'
alias codex3='CODEX_HOME=~/.codex-acct3 codex'Now codex2 opens a session as account 2, full stop.
The Honest Caveats
This uses an undocumented endpoint. There's no official API for Codex usage limits,
so this reads from the same internal backend the CLI uses — it works well until
OpenAI changes something. Occasionally Cloudflare protection tightens and blocks
plain HTTP requests to chatgpt.com, which breaks the fetch temporarily; that's
happened before and typically resolves within a day or two.
Tokens are real credentials. The auth.json files hold actual login tokens. Keep
them out of git, don't sync them to cloud folders, and don't expose port 8788 to
the internet.
Logging out breaks the slot. If you log out of an account in the Codex app rather
than just switching to another, that account's token is invalidated everywhere. To
avoid it, open a new session with CODEX_HOME=~/.codex-acctN codex instead of
hitting Log Out inside the app.
The Result
One glance, every account's limits, all in one place. Green means plenty of room, amber means getting tight, red means switch now, and the reset countdowns tick down live so I always know exactly when each account frees up.
It's a small build — a few hundred lines of vanilla Python. But it replaced a daily routine of logging in and out of several accounts just to answer one question: which one has room right now. That's the kind of tool worth building.