Telegram alerts for Codex subscription quota resets.
codex-resets is a self-hosted Python service that watches Codex subscription
limits through the local app-server and sends a GIF to Telegram when an early
reset is confirmed. It is Telegram-first by design: deploy it to a VPS, add the
bot to a channel or group, and get notified when a quota unexpectedly refreshes.
Unofficial community project. It is not affiliated with OpenAI or Telegram.
- polls Codex subscription limits on a configurable interval;
- distinguishes ordinary and manual resets from unexpected early resets;
- requires two equivalent consecutive observations before sending an alert;
- sends the alert animation through the Telegram Bot API;
- stores baseline, candidate, and event state in SQLite to avoid duplicate alerts;
- optionally accepts
/statusand/ignore-next-resetTelegram commands; - does not use the Platform Admin API, private HTTP endpoints, or OAuth tokens;
- runs without third-party Python runtime dependencies.
Codex CLI app-server
│ account/rateLimits/read
▼
Normalize only the required fields
▼
SQLite: baseline + candidate + events
▼
Reset classifier
│ confirmed early reset
▼
Telegram Bot API → GIF in a channel / group
The service starts codex app-server --stdio as a user with an existing Codex
login, reads account/rateLimits/read, and stores only normalized fields. The
first poll establishes a baseline and never sends an alert.
An early reset is considered confirmed only when all of these conditions hold:
- the used percentage drops materially and the remaining percentage rises;
- the reset time moves forward;
- reset-credit information is available;
- two consecutive polls produce the same result.
Ordinary resets, manual resets, unknown states, and unstable candidates are discarded. Primary and secondary windows from one incident are grouped into one notification, and already-sent events are not repeated.
- Python 3.11+;
- Codex CLI with support for
app-server --stdioandaccount/rateLimits/read; - an existing Codex login in
CODEX_HOMEfor the user running the service; - a Telegram bot created through @BotFather, plus a channel or group where the bot can send animations.
git clone https://github.com/aachebotok/codex-resets.git
cd codex-resets
python3.11 -m venv .venv
. .venv/bin/activate
python -m pip install --no-deps -e .
cp .env.example .env.private
chmod 600 .env.privateFill in .env.private. At minimum, set:
CODEX_HOME=/path/to/authenticated/codex-home
TELEGRAM_BOT_TOKEN=123456:replace-me
TELEGRAM_CHAT_ID=@your_channel_or_chatThe secret file is not loaded automatically. Export it before starting the monitor:
set -a
. ./.env.private
set +a
python -m quota_monitor --status
python -m quota_monitor --onceTo run continuously:
quota-monitorUseful commands:
quota-monitor --help
quota-monitor --status
quota-monitor --once
quota-monitor --ignore-next-reset
python -m unittest discover -s tests -v--ignore-next-reset writes a durable one-shot marker and does not contact
Codex. The marker is consumed only by the next material reset observation.
- Create a bot through @BotFather.
- Add the bot to the target Telegram channel or group.
- Give it permission to send GIFs/animations.
- Set
TELEGRAM_BOT_TOKENand the realTELEGRAM_CHAT_ID. - Run
quota-monitor --onceand check the logs.
TELEGRAM_CHAT_ID=@codexresets in .env.example is only a placeholder. Replace
it with your channel username or numeric chat ID.
Telegram commands are disabled by default. To enable them safely:
TELEGRAM_ENABLE_COMMANDS=true
TELEGRAM_ALLOWED_USER_IDS=123456789,987654321
TELEGRAM_UPDATES_TIMEOUT_SECONDS=20An empty TELEGRAM_ALLOWED_USER_IDS list is fail-closed: channel members cannot
mutate service state. Supported commands are /status and
/ignore-next-reset.
If TELEGRAM_ANIMATION_PATH is not set, the service uses the bundled GIF and
materializes it in the state directory only when an alert is sent. You can
provide a private custom GIF:
TELEGRAM_ANIMATION_PATH=/var/lib/quota-monitor/state/my-alert.gifThe repository includes an installer and a hardened systemd unit for Linux. The
supported layout uses a dedicated quota-monitor user and fixed paths:
| Purpose | Path |
|---|---|
| application | /opt/quota-monitor |
| private env file | /etc/quota-monitor/quota-monitor.env |
| Codex login and SQLite state | /var/lib/quota-monitor/ |
Install Python 3.11+, Codex CLI, and a Codex login for the service user first. Then run the installer from the repository root:
sudo ./deploy/install.sh
sudoedit /etc/quota-monitor/quota-monitor.env
sudo systemctl enable --now quota-monitor
sudo systemctl status quota-monitor --no-pager
sudo journalctl -u quota-monitor -n 100 --no-pagerThe environment file must be owned by root:quota-monitor with mode 0640:
sudo install -o root -g quota-monitor -m 0640 /dev/null \
/etc/quota-monitor/quota-monitor.env
sudoedit /etc/quota-monitor/quota-monitor.env
sudo systemctl restart quota-monitorThe installer does not accept secrets as arguments, does not print environment
values, and rejects non-default paths. The unit uses ProtectSystem=strict,
ProtectHome=read-only, PrivateTmp, a dedicated user, and a restricted
writable state directory.
See deploy/README.md for detailed deployment notes.
- the Bot token is kept only in a private env file and in process memory while calling Telegram;
- the Codex auth home remains a separate sensitive credential store;
- a Platform Admin API key is not used and must not be added to this project;
- the provider removes API/OAuth/token variables from the child
app-serverenvironment; - SQLite and logs contain normalized data only, not raw JSON or secrets;
- Telegram failures are logged only as short, safe error codes.
Never commit .env.private, tokens, SQLite state, or the contents of
CODEX_HOME. If a Bot token appears in logs, an issue, or a backup, revoke it
through BotFather and issue a new one.
The complete template is in .env.example. Main settings:
| Variable | Purpose | Default |
|---|---|---|
CODEX_BIN |
Codex CLI path | codex |
CODEX_HOME |
Codex auth home | unset |
QUOTA_MONITOR_STATE_DIR |
SQLite and runtime state | ~/.local/state/quota-monitor |
QUOTA_MONITOR_POLL_INTERVAL_SECONDS |
polling interval | 60 |
QUOTA_MONITOR_CONFIRMATION_POLLS |
polls required for an alert | 2 |
QUOTA_MONITOR_RESET_SKEW_SECONDS |
ordinary-reset tolerance | 300 |
TELEGRAM_CHAT_ID |
Telegram channel or group | @codexresets placeholder |
TELEGRAM_ANIMATION_PATH |
optional GIF | bundled GIF |
TELEGRAM_ENABLE_COMMANDS |
enable Telegram commands | false |
- the project depends on the local Codex app-server and an existing Codex login;
- the app-server protocol may change with future Codex CLI versions;
- the current configuration fixes the timezone to
Europe/Moscow; - this is not an official Telegram client or a replacement for Platform API monitoring;
- the test suite does not require network access, Codex CLI, or Telegram.
No license has been added yet. Before production use or public forks, choose and add an appropriate license.