# Pi Subscription Usage

[English](README.md) | [简体中文](README.zh-CN.md)

A Pi extension that shows the active account's subscription quota in one consistent view.

Supported providers:

- **OpenAI (ChatGPT subscription)** — separate `Plan limits` and app-limit groups for Pi's `openai` OAuth login, rendered with the existing quota bars. The footer and status event use `Plan limits`, matching the ChatGPT usage page. Also requires `openai-codex` OAuth in Pi for the same ChatGPT account/workspace: its backend credential reads `/wham/usage` for website plan windows (`rate_limit`) and credits, and `/wham/usage/chatpass/apps` for the exact active application registration. Plan and app windows have distinct percentages and reset times; neither substitutes for the other. `App Allowance` is the configured usage cap, not remaining quota. Both credentials participate in cache invalidation. No browser cookies are used. Available account reset tickets are shown as `Account Resets`; redemption uses the companion Codex account's reset endpoint with explicit confirmation, not an app-specific reset endpoint.

- **OpenAI Codex** — 5-hour and weekly quota, model-specific quota, and confirmed reset-credit redemption.
- **OpenCode Go** — 5-hour, weekly, and monthly windows.
- **Grok** — weekly and/or monthly quota using only Pi's `xai` / `xai-auth` OAuth credentials, with account identity verification. A weekly `currentPeriod` with an omitted `creditUsagePercent` is treated as 0% used (proto3 omits zero after reset). Unified SuperGrok billing is still probed from the default monthly endpoint, but that probe is no longer required when the weekly window is already displayable. Windows use the same `5h / 1w / 1m` status format as other providers.
- **Kimi Coding** — 5-hour and weekly windows, plus the membership plan reported by the usage API.

The extension does not implement or modify Codex Fast mode and never rewrites model requests.

## Installation

Install directly from GitHub:

```bash
pi install git:github.com/specode/pi-subscription-usage
```

After the npm package is published, it can also be installed with:

```bash
pi install npm:@specode/pi-subscription-usage
```

For local development:

```bash
pi install /absolute/path/to/pi-subscription-usage
```

Pi packages execute with your full system permissions. Review third-party package source before installing it.

## Usage

Run:

```text
/usage
```

Each invocation bypasses the cache and queries the current provider again. Quota windows use a uniform display with `MM/DD HH:mm` reset times. When a provider reports account metrics, they appear in a separate `Account` section after the quota windows.

Codex results are grouped by quota domain in this order:

1. `Shared Across Models`
2. Model-specific sections
3. `Account`

Windows from different domains are never interleaved. When available, the Codex `Account` section displays the email decoded locally from the active OAuth token. Run `/usage` again whenever you want to refresh; the command does not show refresh, provider-switching, or all-provider menus.

The reset menu appears for OpenAI and Codex only when redeemable reset credits are verified. Grok's current API exposes quota windows and natural reset times, but no verified manual-reset endpoint or reset-credit count, so the extension never invents a reset action. Grok windows still render through the same `/usage` bars and status event as Codex, OpenCode Go, and Kimi.

## Configuration

Create `~/.pi/agent/subscription-usage.json` for a global setting, or `.pi/subscription-usage.json` in a trusted project to override it:

```json
{
  "displayMode": "used"
}
```

`displayMode` accepts:

- `"remaining"` — show quota remaining (default, preserving the existing behavior).
- `"used"` — show quota consumed.

The setting applies to the footer status, `/usage` quota bars, and the structured status event. Run `/reload` after editing the file.

## OpenAI / Codex reset safety

OpenAI mode uses the same `/wham/rate-limit-reset-credits` and `/consume` endpoints as the ChatGPT usage page. Only explicit, available, plan-supported, unexpired `codex_rate_limits` tickets are offered; failed listing never falls back to automatic redemption. Tickets reset server-defined account windows, **not necessarily the current app's window**. The confirmation states this scope. Reset availability failure does not hide plan/app quota; successful redemption invalidates both providers' usage caches.

Before redeeming a reset credit, the extension:

1. Verifies that the active OpenAI or Codex model and usage account have not changed.
2. Verifies that the runtime token exactly matches the OAuth account stored by Pi through `/login`. OpenAI mode checks both stored credentials and rechecks application matching before redemption.
3. Shows the reset that will be consumed and asks for explicit confirmation. `Cancel (Default)` is always the first option; only deliberately choosing the second option continues.
4. Uses a unique request ID and reuses it across retries.

## Status integration

The extension publishes two status layers:

- A plain `setStatus` string without provider names or icons, such as `5h 99% ↻2h13m · 1w 85% ↻3d4h · 1m 60%`. `↻` marks the countdown to each window's reset, shown only when the provider reports a future reset time. The footer refreshes every 5 minutes and after each agent turn, so the countdown can lag by up to about 5 minutes.
- Structured window data through the `subscription-usage/status/v1` event.

Windows are always ordered as `5h / 1w / 1m / other`. Other extensions can consume the structured event to provide their own icons, colors, and layout without parsing display text. Ready events include `displayMode`; each window includes `displayPercent`, `remainingPercent`, and `usedPercent`. Consumers should render `displayPercent` while using the explicit remaining/used fields for semantic decisions such as colors or alerts. When the provider reports a future reset time, a window also carries `resetCountdown` (for example `2h13m`), computed at publish time with the same format and refresh cadence as the footer text; consumers can show it as-is instead of formatting `resetsAt` themselves.

## Security boundaries

- Usage queries resolve credentials only through `ctx.modelRegistry.getProviderAuth()`.
- Account reset additionally reads Pi's stored OAuth credentials through the public `readStoredCredential()` API, solely to verify that it exactly matches the active runtime account before redemption.
- Grok never reads `~/.grok/auth.json` and never accepts an API key in place of subscription OAuth.
- Credentials are never written to caches, sessions, the status line, or error messages. Cache keys contain only in-process HMAC fingerprints.
- The Codex email is decoded locally for the `/usage` account panel and is not included in the footer or structured status event.
- Credentials are sent only to the corresponding official domains. Custom proxies and custom base URLs are rejected.
- Account reset redemption (OpenAI / Codex) is the only write operation. It is shown only when redeemable credits exist and always requires explicit confirmation.

## Development

Requirements:

- A current Pi installation.
- A Node.js version that can run TypeScript files directly for the test suite.

Run the tests:

```bash
npm test
```

Inspect the npm package contents:

```bash
npm run pack:check
```

Load the extension directly without installing it:

```bash
pi --no-extensions --offline -e ./index.ts --list-models
```

## Stability

OpenAI app usage also depends on an undocumented ChatGPT endpoint. If the companion Codex login is missing, sign in to **OpenAI Codex** through `/login` without changing the active OpenAI model. An account/workspace mismatch, missing registration, or missing windows produces an error rather than displaying another account's quota. `App Allowance` is the configured share the app may use, not its remaining percentage. `Source` identifies this as the matching app in Pi's Codex account; matching application IDs is not independent cryptographic verification of both token identities.

Codex reset, Grok billing, and Kimi usage rely on undocumented provider APIs that may change. When an API fails, the extension reports the query error and does not fall back to uncontrolled credential or proxy paths.

## License

[MIT](LICENSE). See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for adapted third-party sources and licenses.
