UsageWidget is a self-hosted iOS 26+ app and large Home Screen widget for monitoring CodexBar usage. A small Go service runs on Linux, macOS, or Windows, normalizes every enabled provider, stores history in SQLite, and sends APNs alerts and WidgetKit refreshes to the phone.
┌──────────────┐ Tailscale HTTPS ┌──────────────────┐ Unix socket ┌─────────────────┐
│ iPhone app │ ───────────────────► │ usagewidgetd │ ──────────────► │ CLI collector │
│ + widget │ ◄── APNs/WidgetKit ─ │ Go API + SQLite │ │ CodexBar session│
└──────────────┘ └──────────────────┘ └─────────────────┘
Linux uses the isolated Unix-socket collector shown above. Native macOS and Windows runs use an exact CodexBar CLI path or a configured CodexBar HTTP URL.
- Discovers Codex, Claude, Grok, and other providers from CodexBar instead of hard-coding a provider list.
- Shows every rate window, reset time, remaining capacity, freshness state, and a burn-rate forecast after enough history has accumulated.
- Supports global, per-provider, and per-window alert rules, quiet hours, and optional danger reminders.
- Detects threshold crossings, scheduled resets, early “Tibo” resets, and reset-credit increases without alerting on a first-seen baseline.
- Keeps provider visibility and ordering on the server, so hidden providers are omitted from phone-facing snapshots and alerts.
- Onboards the iPhone by manual entry or a private setup QR generated by the installer.
- Runs from Linux, macOS, or Windows and installs the native server on a Linux, macOS, or Windows SSH target—no repository clone or local build required.
- Detects amd64/arm64 automatically and preserves configuration and SQLite data when the installer is rerun for an update.
- Includes redacted health and device-readiness checks plus a targeted APNs and WidgetKit delivery test.
Provider credentials never leave the machine running CodexBar. On Linux they remain isolated in the collector account; desktop mode runs as the signed-in user. The phone API does not return raw CodexBar payloads. The app and widget share the bearer token through a Keychain access group; App Group defaults contain only cached display data and preferences.
UsageWidget began with a personal frustration. I first used Codex models through Claude Code, where I could not reliably see my usage, and I had to keep checking X to learn when limits might reset. CodexBar made the data available on my Mac, but it did not provide the mobile experience I wanted: a quick look at my phone while away from my desk, without opening my Mac and navigating through several menus. That led to the iOS app, Home Screen widget, reset timings, forecasts, and alerts in this repository.
Codex was part of the project from its beginning. I used it to plan and implement work across the SwiftUI and WidgetKit frontend, Go server, Linux deployment, Cloudflare-hosted installer endpoint, landing page, tests, and TestFlight release preparation. It was particularly valuable near release, when it could inspect the repository as a whole for integration, security, and packaging problems that were difficult to spot one file at a time.
The clearest example of work completed with GPT-5.6 is the installation and
onboarding flow. An initially manual sequence of server commands became a
single curl-based installation path followed by QR-code setup in the iOS app.
This required coordinated changes to the installer, server configuration,
Cloudflare Worker routing on the project domain, QR payload, and iOS
registration flow. GPT-5.6's ability to plan and carry a long task across those
boundaries made that integration practical.
I remained responsible for the product direction and final decisions. I chose the problem, the self-hosted Linux architecture, the privacy boundary, the UI and visual preferences, and the behavior I wanted from resets and alerts. My workflow was iterative: use each working version, identify what felt wrong, then direct Codex to revise it. I accepted, changed, or rejected its suggestions based on how the complete system behaved rather than treating generated code as finished work.
Verification combined automated Go, installer, CLI, and iOS build checks with hands-on testing on physical iPhones running iOS 26 and iOS 27. That process also uncovered a server data-fetching approach from an earlier implementation that interacted poorly with rate limits; Codex helped trace it across the collection path and replace it with the current design.
Codex and GPT-5.6 were development tools, not runtime dependencies. UsageWidget does not send requests to GPT-5.6: it reads usage data from CodexBar and serves that data through the self-hosted system described below. Without Codex and GPT-5.6, UsageWidget would not have existed.
For Build Week verification, the primary Codex /feedback session is
019f74b0-fe97-7dc3-bb40-0e7b5c0274a7. The public source repository is
github.com/EdmundLimBoEn/UsageWidget.
| Path | Purpose |
|---|---|
server/ |
Go service, collector, SQLite store, event engine, APNs, and HTTP APIs |
ios/ |
SwiftUI app, WidgetKit extension, shared models, and XcodeGen project |
cli/usagewidget |
Local/server operations CLI |
server-install.sh |
Linux release installer and usagewidget-admin lifecycle commands |
server-setup.sh |
Interactive Mac-to-Linux source installation |
server/deploy/start-* |
Native macOS and Windows foreground launchers |
docs/ |
Historical implementation plans and design records |
| Host | Support | Upstream source |
|---|---|---|
| Ubuntu 22.04/24.04, Debian 12 | Production service install (amd64/arm64) | Isolated CodexBar CLI collector |
| macOS | Native foreground server (Intel/Apple silicon) | Local CodexBar CLI or CODEXBAR_URL |
| Windows 10/11 | Native foreground server (amd64/arm64) | CODEXBAR_URL or a compatible CLI build |
The managed Linux service remains the recommended always-on deployment because it provides service management and separates the server from provider credentials. Desktop packages are useful for personal machines, testing, and hosts that are already kept signed in.
The hosted installer supports the full controller-to-target matrix: run it from Linux, macOS, or Windows and point it over SSH at Linux, macOS, or Windows. Linux and macOS controllers share the Unix command; Windows uses PowerShell:
# Linux or macOS
curl -fsSL https://usagewidget.edmundlim.systems/install.sh | bash# Windows PowerShell
irm https://usagewidget.edmundlim.systems/install.ps1 | iexBoth commands ask for the SSH user and target, detect the target OS and amd64/arm64 architecture, verify the matching GitHub release on that target, configure its private Tailscale route, and print the iPhone setup QR back in the controller terminal. Existing configuration and databases are retained.
The supported release hosts are Ubuntu 22.04, Ubuntu 24.04, and Debian 12 on amd64 or arm64. The host needs systemd, Tailscale, an unprivileged account with a working CodexBar session, and root or sudo access for installation.
The fastest setup downloads the latest release for the host architecture, verifies its checksum, installs both services, and prints the private iPhone setup QR:
curl -fsSL https://usagewidget.edmundlim.systems/install.sh | bashThe installer first asks for the SSH destination, then which unprivileged Linux
account owns the working CodexBar session. It invokes sudo only for remote
system installation steps. You do not
need to clone this repository or add command-line flags.
When installation finishes, scan the QR in UsageWidget; the server URL and
generated bearer token are encoded for you. The installer can be rerun safely
for updates while preserving configuration and SQLite data. This command is
for the supported Ubuntu and Debian server hosts.
If you already downloaded and extracted a release bundle, run the packaged installer directly instead:
sudo ./server-install.sh install --collector-user YOUR_LOGIN
sudo usagewidget-admin doctor
sudo usagewidget-admin qrThe installer verifies the release contents, installs CodexBar when needed,
preserves configuration and SQLite data on reruns, binds the API to
127.0.0.1:8377, configures the Tailscale Serve /usagewidget route, and
prints a setup QR when qrencode is available.
From a development Mac or Linux machine, the interactive source-install path builds the correct server architecture and runs the same installer remotely:
./server-setup.shSee the deployment guide for prerequisites, APNs configuration, backups, updates, recovery, and manual installation. See the redeploy runbook for routine source deployments.
From a Linux or macOS controller, run the no-flag Unix installer and select the target Mac over SSH (Windows controllers use the PowerShell command above):
curl -fsSL https://usagewidget.edmundlim.systems/install.sh | bashIt detects Intel or Apple silicon remotely, verifies and installs the matching
release under ~/Library/Application Support/UsageWidget/App, registers a
LaunchAgent, configures Tailscale Serve, and prints the QR locally. It uses a
working target-side codexbar/CodexBarCLI or a private CodexBar usage URL. Saved
configuration and SQLite data remain in the parent UsageWidget directory and
survive application updates. Keep the terminal open. For a source checkout,
build first with
(cd server && go build -o ../bin/usagewidgetd ./cmd/usagewidgetd), then run
server/deploy/start-macos.sh with USAGEWIDGET_DAEMON pointing to that binary.
From a Windows controller, run the native no-flag installer and select the target Windows machine over SSH (Linux/macOS controllers use the Unix command):
irm https://usagewidget.edmundlim.systems/install.ps1 | iexIt detects x64 or ARM64 remotely, verifies and installs the native bundle under
%LOCALAPPDATA%\UsageWidget\App, registers a persistent scheduled task,
configures Tailscale Serve, and prints the QR locally. It asks for a private
CodexBar usage URL when no compatible target-side CLI exists. The
SQLite database and configuration stay in %LOCALAPPDATA%\UsageWidget, outside
the replaceable application directory. CodexBar currently publishes
standalone CLI archives for macOS and Linux, not Windows, so Windows normally
uses a private CodexBar HTTP endpoint on another machine. A compatible Windows
CLI can instead be selected with -CodexBarBin C:\path\to\codexbar.exe.
Do not expose that upstream endpoint or UsageWidget port 8377 publicly.
Go 1.26.5 or newer is required by server/go.mod.
cd server
export USAGEWIDGET_TOKEN="$(openssl rand -hex 32)"
export CODEXBAR_URL=http://127.0.0.1:8765/usage
go run ./cmd/usagewidgetdThe data source is selected in this order:
CODEXBAR_CMD, a legacy command override for an account that owns the provider sessions.CODEXBAR_URL, an HTTP development override.CODEXBAR_BIN, an exact CLI path used by native desktop installs.COLLECTOR_SOCKET, the Linux production default (/run/usagewidget/codexbar.sock) served by the isolated collector.
Disabled CodexBar providers remain absent instead of becoming permanent error rows.
cd ios
xcodegen generate
open UsageWidget.xcodeprojSelect your Apple Development team and build to an iOS 26+ device. In the app, scan the installer QR or enter the Tailscale HTTPS base URL and bearer token, then test the connection. Grant notification permission and add the Usage large widget from the Home Screen gallery.
Unsigned CI build:
xcodebuild -scheme UsageWidget -destination 'generic/platform=iOS' \
CODE_SIGNING_ALLOWED=NO buildThe default identifiers are:
- App Group:
group.systems.edmundlim.usagewidget - App:
systems.edmundlim.UsageWidget - Widget:
systems.edmundlim.UsageWidget.widget
Replace them before distributing your own build. WidgetKit timelines and push refreshes are system-budgeted; a one-minute server poll does not guarantee a one-minute Home Screen redraw.
Install or link cli/usagewidget into your PATH. Local configuration is read
from ~/.config/usagewidget/env with mode 600; the installed server CLI
automatically uses /etc/usagewidget/env and the loopback API.
usagewidget env sync # copy the server token into local config
usagewidget health
usagewidget snapshot
usagewidget settings
usagewidget qr # show the private iPhone setup QR again
usagewidget poll # force a real collection cycle
usagewidget deploy
usagewidget logs -f
usagewidget statusRun usagewidget help for the complete command list and environment variables.
Every main API route requires
Authorization: Bearer <USAGEWIDGET_TOKEN>.
| Method | Path | Purpose |
|---|---|---|
GET |
/v1/health |
Redacted service, collector, database, polling, APNs, and delivery health |
GET |
/v1/snapshot |
Visible normalized providers, windows, forecasts, and freshness |
GET / PUT |
/v1/settings |
Polling, provider display, and alert-rule settings |
POST |
/v1/devices |
Register or rotate APNs and WidgetKit tokens |
DELETE |
/v1/devices/{deviceID} |
Remove a registered device |
POST |
/v1/poll |
Force one collection cycle |
GET |
/v1/readiness/{deviceID} |
Get redacted server and device readiness checks |
POST |
/v1/readiness/{deviceID}/test |
Send a targeted audible alert and widget delivery test |
Defaults are a five-minute poll, an early alert at 10% used, a danger alert at 10% remaining, no repeated danger reminders, and quiet hours disabled. Allowed poll intervals are 1, 5, 15, 30, and 60 minutes; repeat intervals are never, hourly, every three hours, or every six hours.
Rules inherit from global → provider → window. Hiding a provider removes it from the widget and disables its alerts. During quiet hours, automatic alerts are delivered passively; outside quiet hours they remain audible. The explicit readiness test is always audible.
Forecasts use up to 24 hours of samples from the current reset cycle and appear only after at least three increasing samples spanning 30 minutes and one percentage point. Forecasts are omitted from stale snapshots.
Use Release readiness in the iOS app to inspect server, APNs, and device
registration state and to send a targeted audible alert and widget refresh.
Run go test ./... in server/, bash tests/installer_test.sh, and the
unsigned Xcode build above before producing a distribution archive.
TestFlight archive and export:
cd ios
xcodebuild -project UsageWidget.xcodeproj -scheme UsageWidget \
-configuration Release -destination 'generic/platform=iOS' \
-archivePath build/UsageWidget.xcarchive \
-allowProvisioningUpdates archive
xcodebuild -exportArchive \
-archivePath build/UsageWidget.xcarchive \
-exportPath build/TestFlight \
-exportOptionsPlist ExportOptions.plist \
-allowProvisioningUpdatesRelease tags (v*) run Go tests, shell syntax checks, installer tests, and
build Linux, macOS, and Windows amd64/arm64 bundles through GitHub Actions.
Read SECURITY.md before exposing a service or publishing the repository. Apple signing, APNs, private networking, release publication, and device verification steps are tracked in HUMANS.md.