Your OpenAI Codex usage, always on display.
codex-usage-epd pushes your Codex usage — remaining quota and token totals — to
a 4.2" 400×300 three-colour e-paper panel over Bluetooth LE. It works with
displays running the EPD-nRF5 firmware.
- Quota at a glance — 5-hour and weekly windows with used/remaining percentages and reset times.
- Today's token usage — a total across all models, plus your top three models shown as bars proportional to the most-used model.
- Optional 7-day history — a compact line chart for the seven completed calendar days before today.
- Credits balance when your plan includes one.
- Red alert bars when remaining quota drops below your warning threshold.
- Set-and-forget updates — refresh automatically on a macOS launchd schedule.
- macOS with Bluetooth LE support
- Python 3.10 or newer
- A ChatGPT/Codex login on the same Mac (
~/.codex/auth.jsonwithtokens.access_token) - A 4.2" 400×300 black/white/red panel with an SSD1683/SSD1619 driver and model
ID
0x02
Pick whichever Python tool you already use:
# pipx — recommended for command-line applications
pipx install codex-usage-epd
# uv
uv tool install codex-usage-epd
# pip
pip install codex-usage-epdTo install from source instead:
git clone https://github.com/hunterMG/codex-usage-epd.git
cd codex-usage-epd
pipx install . # or: uv tool install . / pip install .Upgrade later with the matching command (pipx upgrade codex-usage-epd,
uv tool upgrade codex-usage-epd, or pip install --upgrade codex-usage-epd).
-
Create a configuration file
codex-usage-epd --init
The command prints the config path. When installed as a package it writes to
~/.config/codex-usage-epd/codex_usage_epd.yaml; in a source checkout it writes toconfig/codex_usage_epd.yaml. -
Point it at your display — open the config and set
ble.deviceto your panel's MAC address or Bluetooth name, or leave it asautoto scan forNRF_EPD. -
Try it without hardware
codex-usage-epd --selftest # sample data, no network or display needed codex-usage-epd --dry-run # live data, saves preview.png
-
Send it to the panel
codex-usage-epd --once
Paste this prompt into Codex or another coding agent:
Install https://github.com/hunterMG/codex-usage-epd on this computer. Read the
README first, check that the prerequisites are available, clone the repository
into an appropriate user directory, install it with an appropriate Python tool,
generate the configuration file, and run the self-test. Do not print, copy, or
modify my Codex authentication token. Tell me what configuration still needs my
input, and ask for confirmation before installing or starting the launchd
background agent.
| Command | Description |
|---|---|
codex-usage-epd --init |
Generate a config file from the template |
codex-usage-epd --selftest |
Render sample data and verify encoding without network or display |
codex-usage-epd --dry-run |
Fetch live usage and render preview.png without Bluetooth |
codex-usage-epd --probe |
Connect to the display and print its config and MTU |
codex-usage-epd --test-screen |
Clear and refresh the panel to check the firmware path |
codex-usage-epd --once |
Fetch, render, and push to the display once |
codex-usage-epd --loop |
Push every schedule.interval_minutes forever |
Options can be combined with the commands above:
| Option | Description |
|---|---|
--config <path> |
Use a specific YAML config instead of the default |
--force |
With --init, overwrite an existing config |
--font <path> |
Override render.font |
--sample |
Use synthetic sample data instead of fetching usage |
--show-history / --no-show-history |
Override render.show_history |
--debug |
Dump the raw usage response to tmp/usage_dump.json |
Without --config, the config is loaded from the checkout's
config/codex_usage_epd.yaml, then
~/.config/codex-usage-epd/codex_usage_epd.yaml, then the bundled template.
Create a config with codex-usage-epd --init, then edit the generated YAML.
The most useful settings are:
| Key | Default | Description |
|---|---|---|
display.width / display.height |
400 / 300 |
Panel resolution in pixels |
display.model_id |
0x02 |
EPD model ID (0x02 for SSD1619 400×300 BWR) |
display.sleep_after_push |
false |
Send SLEEP after pushing. Keep false; sleeping early aborts the refresh |
ble.device |
auto |
auto, a MAC address, or a Bluetooth name substring |
ble.mtu |
247 |
Bluetooth MTU |
ble.scan_timeout |
10 |
Seconds per scan attempt |
ble.scan_retries |
3 |
Scan attempts before giving up on missed advertisements |
ble.interleave |
50 |
Writes per response acknowledgement (matches the web client) |
ble.pacing_ms |
0.0 |
Delay between writes (0.0 is back-to-back) |
ble.hold_after_refresh |
20 |
Seconds to stay connected while the panel refreshes |
ble.patch_wakeup_pin |
true |
Keeps the panel advertising after its sleep timeout |
ble.slot |
0 |
Image slot for slot-based firmware; auto picks a free slot, -1/none disables SET_SLOT |
codex.auth_file |
~/.codex/auth.json |
Location of the OAuth tokens |
codex.timeout |
15 |
Usage request timeout in seconds |
render.font |
auto | Path to a .ttf font; empty means auto-detect |
render.warn_threshold |
20 |
Remaining percentage that turns a bar red |
render.preview |
preview.png |
Filename for the rendered preview |
render.show_history |
false |
Show the "Last 7 days" chart |
schedule.interval_minutes |
60 |
Interval used by --loop |
codex also reads chatgpt_base_url from ~/.codex/config.toml when set.
The launchd agent runs codex-usage-epd from .venv/bin/ inside a source
checkout. If you have not already done so, create that environment and install
the project into it:
python3 -m venv .venv
.venv/bin/pip install .
./deploy/install.shThe installer fills in the checkout path, writes
~/Library/LaunchAgents/com.codex-usage-epd.plist, and starts the agent. It
refreshes the display every 60 minutes. To remove it later:
launchctl bootout gui/$(id -u)/com.codex-usage-epd
rm ~/Library/LaunchAgents/com.codex-usage-epd.plistYour Codex tokens are read locally from ~/.codex/auth.json and are never
logged, printed, or committed. Usage data is fetched directly from OpenAI; no
third-party service is involved.
- Display not found — make sure the panel is powered and nearby. Try
codex-usage-epd --probe; if scanning still fails, setble.deviceto the panel's MAC address or Bluetooth name instead ofauto. - The screen stays blank or refreshes partway — keep the panel connected to
USB power and leave
display.sleep_after_push: false. You can also increaseble.hold_after_refresh. - Authentication errors — sign in to Codex again on this Mac and confirm
~/.codex/auth.jsonexists, or updatecodex.auth_file. - Token usage is missing — token totals are read from
$CODEX_HOME/sessions(or~/.codex/sessions) andarchived_sessions. Confirm those directories contain local Codex session logs. - Colors look wrong in the preview — the panel has no greys, only black, white, and red. Light grey text intentionally renders as white.
Development notes, project layout, and preview checks are in docs/development.md.
GNU AGPL v3.0 or later — see LICENSE.
