# Agent Notes

- `Registry dependency`: Use published `@llblab/pi-command-fast@^0.1.0` with aligned registry lock metadata. Local folder links are only for explicitly requested development tests; rebuild the library's `dist/` after source edits and restore registry dependency/locks before consumer publication.
- `Pi baseline`: Every declared `@earendil-works/*` peer requires ≥1.0.0. Keep Pi peer lock identities aligned and validate against that host generation.
- `Statusline-first scope`: Own usage state + usage mode; keep quota reporting zero-configuration and optional Fast on the existing terminal status.
  - Trigger: Considering commands, menus, persisted settings, or notification output.
  - Action: Prefer deleting the surface unless it is required for the optimistic TUI status widget, optional `pi-telegram` `/start` status-line mirror, or the argument-free shared `/fast`. Register only the `anthropic` provider handler through `@llblab/pi-command-fast` on session_start; release on session_shutdown. Never register the command directly or gate it on quota auth. Claude Fast eligibility is consumer-owned: permit the `claude-opus-` family without a version allowlist; warn `Fast mode is supported only for Opus` for other families without writes. Family eligibility is not proof of backend support; preserve server capability/billing errors. For rejected models, ignore stale unsupported overrides in status/request adaptation, and leave Codex eligibility unchanged. The library owns session WeakMap/reload arbitration and generic JSONC; `lib/fast.ts` owns Claude semantics; require Pi ≥1.0.0 for its assembled-beta payload contract, rather than copying upstream beta defaults. ON is `speed: "fast"` in the current model override; OFF deletes the property. Preserve existing request speed/betas, append the required Fast beta to the native assembled list rather than replacing a header, and keep Fast out of quota state. The optional Telegram row reads the active model's eligible Fast preference at render time and appends plain-text ` fast` (or shows `fast` alone without quota). Toggle redraws through the final terminal boundary without a quota request or success notification; unreadable config fails closed for Fast only.
- `Domain boundaries`: `index.ts` is export-only; `lib/extension.ts` composes lifecycle/Fast registration and request hooks. `lib/status.ts` owns refresh orchestration and terminal timers; `usage-store.ts` owns claims/fencing/mutex, `query.ts` owns OAuth/HTTP, `usage.ts` owns quota normalization, `status-format.ts` owns presentation, and `telegram.ts` owns optional registration. Preserve mature quota/auth/leadership behavior, keep imports acyclic with no domain importing the entrypoint, and keep domain-focused tests in `tests/`. Do not merge usage extensions or redesign polling to add Fast.
- `Optimistic refresh`: Preserve the last good statusline bar during refresh and transient failures.
  - Trigger: Updating quota polling or error handling.
  - Action: Do not collapse the bar while a request is in flight; only show `n/a` or `error` after repeated failures or no usable quota.
- `Adaptive compact status`: Match the status representation to the server-provided quota windows.
  - Trigger: Changing statusline formatting.
  - Action: When both windows exist, keep the classic dual bar with 20 top steps for the 5-hour window and 20 bottom steps for the weekly window. When only one weekly window exists, show its rounded remaining percentage directly instead of using a bar.
- `Weekly reset countdown`: Append the weekly reset countdown whenever the available weekly window exposes a reset time.
  - Trigger: Changing reset-time normalization or statusline refresh cadence.
  - Action: Map `five_hour` to the primary window and `seven_day` to the secondary (weekly) window; treat a sole window as weekly. Keep `d` labels rounded upward in 144-minute day-tenth steps above 24h, show 24h..1h labels in upward-rounded 6-minute hour-tenth steps, keep `m`/`s` labels floored, and hold `0s` until a successful quota refresh reports the next window.
- `Pi auth only`: Usage is read from `https://api.anthropic.com/api/oauth/usage` with the Pi `anthropic` provider OAuth token (`sk-ant-oat…`) and the `anthropic-beta: oauth-2025-04-20` header.
  - Trigger: Touching auth or adding usage sources.
  - Action: Do not add fallbacks, CLI probes, or API-key paths; API keys have no subscription quota, so report `n/a`. `utilization` is a used percent.
- `Rate-limit discipline`: Quota polling must be shared across instances; HTTP 429 triggers shared backoff.
  - Trigger: Changing refresh cadence, retries, locking, or adding fetch paths.
  - Action: Keep the single shared-state protocol in `lib/usage-store.ts`, orchestrated by `lib/status.ts` (leader refreshes every minute, takeover after 90 seconds by claiming leadership before fetching, a non-waiting OS-backed SQLite mutex around claiming and fenced publication, atomic writes, shared failure backoff). Always re-read the file for request authorization (`owner` + `claimId` + lease) and publication; do not use an in-memory ownership fallback. Lock failures and failed claim writes must deny requests. `mutex.sqlite` stores no quota or leadership data: never unlink/replace it while instances run or evict a paused holder; close or process death releases the mutex. Keep network calls outside critical sections. Instances otherwise only read the file; never add per-instance polling or probing requests.
