Skip to content

About

No description, website, or topics provided.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

UsageWidget

UsageWidget is a self-hosted iOS 26+ app and large Home Screen widget for monitoring AI coding capacity. A small Go service runs on Linux, macOS, or Windows, normalizes CrossUsage limits into quota-style windows, 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  │                 │ crossusage-cli  │
└──────────────┘                      └──────────────────┘                 └─────────────────┘

Linux uses the isolated Unix-socket collector shown above. Native macOS and Windows runs can point at crossusage-cli or a local CrossUsage http://127.0.0.1:6736/v1/limits URL.

What it does

  • Prefers plan/quota gauges (Cursor Plan + Auto, Codex/Claude 5h/7d windows) and drops API spend dashboards (OpenAI Admin API, OpenRouter, and similar) plus telemetry-only providers.
  • Includes Cursor, Codex, Claude Code, Copilot, Gemini, Grok, and Devin in the default provider order.
  • Shows remaining capacity, reset time, and projected runouts (100% in … / ~N% by reset) as soon as a window + reset clock exist; history-based burn rates still enrich forecasts after enough samples.
  • Supports global and per-provider alert rules, quiet hours, and optional danger reminders.
  • Detects threshold crossings, scheduled resets, early usage drops, 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 checks plus a targeted APNs and WidgetKit delivery test.

Provider credentials never leave the machine running CrossUsage. On Linux they remain isolated in the collector account; desktop mode runs as the signed-in user. The phone API does not return raw upstream payloads. The app and widget share the bearer token through a Keychain access group; App Group defaults contain only cached display data and preferences.

Repository map

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/ Technical brief for maintainers

Install a server

Host Support Upstream source
Ubuntu 22.04/24.04, Debian 12 Production service install (amd64; arm64 if crossusage-cli is already on PATH) Isolated CrossUsage collector
macOS Native foreground server (Intel/Apple silicon) Local crossusage-cli or CROSSUSAGE_URL
Windows 10/11 Native foreground server (amd64) crossusage-cli or http://127.0.0.1:6736/v1/limits

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 | iex

Both 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.

Linux

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 CrossUsage CLI 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 | bash

The installer first asks for the SSH destination, then which unprivileged Linux account owns the working CrossUsage 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 qr

The installer verifies the release contents, installs CrossUsage CLI 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.sh

See the deployment guide for prerequisites, APNs configuration, backups, updates, recovery, and manual installation. See the redeploy runbook for routine source deployments.

macOS

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 | bash

It 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 crossusage-cli or a CrossUsage CROSSUSAGE_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.

Windows

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 | iex

It 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 CrossUsage CLI or local CROSSUSAGE_URL when none is on PATH. The SQLite database and configuration stay in %LOCALAPPDATA%\UsageWidget, outside the replaceable application directory. CrossUsage publishes a Windows CLI zip and a local HTTP API on 127.0.0.1:6736. A CLI path can be selected with -CrossUsageBin C:\path\to\crossusage-cli.exe. Do not expose that upstream endpoint or UsageWidget port 8377 publicly.

Local server development

Go 1.26.5 or newer is required by server/go.mod.

cd server
export USAGEWIDGET_TOKEN="$(openssl rand -hex 32)"
export CROSSUSAGE_BIN="$(command -v crossusage-cli)"
# optional Devin remaining-credits collector:
# export DEVIN_SERVICE_KEY="your-billing-read-service-key"
# or talk to a running CrossUsage tray app:
# export CROSSUSAGE_URL=http://127.0.0.1:6736/v1/limits
go run ./cmd/usagewidgetd

The data source is selected in this order:

  1. CROSSUSAGE_CMD, a full CrossUsage command override.
  2. CROSSUSAGE_URL, usually http://127.0.0.1:6736/v1/limits.
  3. CROSSUSAGE_BIN, an exact crossusage-cli path. The collector runs limits for the catalog plugin ids.
  4. Collector socket (Linux production default /run/usagewidget/collector.sock).

Devin is collected from Cognition's GetTeamCreditBalance API, not from a hardcoded key. Set DEVIN_SERVICE_KEY to a Devin Desktop / Windsurf service key with Billing Read. On Linux, put it in /etc/usagewidget/collector.env so the key stays with the collector account. On macOS or Windows, put it in the same env file as the other server variables. If the key is unset, Devin is omitted and the rest of the poll still runs. If the key is set and the request fails, Devin appears as that provider error instead of failing Cursor, Codex, and the other plugins.

Providers without usage-limit gauges are omitted instead of becoming permanent noise rows.

Connect the iPhone

cd ios
xcodegen generate
open UsageWidget.xcodeproj

Select 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 build

The 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.

Operations CLI

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 status

Run usagewidget help for the complete command list and environment variables.

HTTP API

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

Alerts and forecasts

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.

Release verification

Use Delivery 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 \
  -allowProvisioningUpdates

Release tags (v*) run Go tests, shell syntax checks, installer tests, and build Linux, macOS, and Windows amd64/arm64 bundles through GitHub Actions.

Security and human steps

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.

The public source is github.com/EdmundLimBoEn/UsageWidget. Codex and GPT-5.6 were used to build the project. They are not runtime dependencies. The running app reads CrossUsage limits data on your server, plus Devin team credit balance when DEVIN_SERVICE_KEY is set.

About

No description, website, or topics provided.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages