pi-usage-hub

Usage hub for pi — provider quota/balance registry with cache, /usage-hub panel, and pull API

Packages

Package details

extension

Install pi-usage-hub from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-usage-hub
Package
pi-usage-hub
Version
1.0.6
Published
Jul 22, 2026
Downloads
866/mo · 866/wk
Author
ouzhenkun
License
MIT
Types
extension
Size
430.9 KB
Dependencies
0 dependencies · 2 peers
Pi manifest JSON
{
  "extensions": [
    "./index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-usage-hub

Track provider quotas and balances in pi — /usage-hub panel, session stats, and a pull API for footer integration.

npm version License: MIT

Why

Checking separate dashboards for DeepSeek, NewAPI relays, xAI, Kiro, OpenCode Go, and ARK breaks flow. pi-usage-hub brings their quotas and balances into one TUI panel while keeping footer integration optional and pull-based.

Install

pi install npm:pi-usage-hub

Commands

Command Description
/usage-hub Show quotas and balances for detected providers
/usage-hub session Show local session token and cost stats
/usage-hub login <name> Open browser login for a cookie-based provider

Inside the panel, Tab switches between Quota and Session. In the Quota view, ↑↓ scrolls when content overflows.

pi-usage-hub quota panel

Configuration

Create ~/.pi/agent/pi-usage-hub.json. Provider order is preserved in the panel.

{
  "providers": [
    {
      "type": "deepseek",
      "apiKey": "sk-..."
    },
    {
      "name": "xh",
      "type": "newapi",
      "matchProviders": ["xh-cc", "xh-glm"],
      "host": "https://example.com",
      "token": "...",
      "userId": "1"
    },
    {
      "name": "ocg",
      "type": "opencode-go",
      "workspaceId": "wrk_...",
      "matchProviders": ["opencode-go"]
    },
    { "type": "ark" },
    {
      "type": "xai",
      "matchProviders": ["xai-auth", "xai", "grok-cli"]
    },
    { "type": "kiro" }
  ]
}

Common fields

Field Required Description
type yes Built-in provider factory
name no Instance key; defaults to type, then type-2, type-3, and so on
matchProviders no Additional model.provider values mapped to this entry
shortLabel / label no Override the footer label or panel title

Provider types

Type Credentials Notes Website
deepseek apiKey Account balance deepseek
newapi host, token, userId Balance and today's spend; supports multiple instances newapi
opencode-go workspaceId; optional auth Uses the configured auth cookie or macOS Chrome opencode
ark optional cookie, csrfToken Uses the configured Cookie header or macOS Chrome 火山引擎
xai Reads auth.json or ~/.grok/auth.json x.ai/grok
kiro Reads the Kiro OAuth entry from auth.json kiro.dev

For NewAPI, token is the system access token (not a chat sk- token), and userId is sent as New-Api-User. See Authentication and Generate access token.

For ARK and OpenCode Go, configured cookie / auth values take priority over Chrome. Manual credentials disable /usage-hub login for that entry; replace them when they expire. Automatic Chrome cookie reading is macOS only.

Related auth packages

These are companion packages, not npm peer dependencies:

Type Companion Purpose
xai pi-xai-oauth /login xai-auth writes the OAuth entry to auth.json
kiro pi-provider-kiro-dev Provides /login kiro, models, and the auth.json entry

pi-usage-hub only reads those credentials; it does not run their OAuth flows.

Built-in providers cover the integrations used and smoke-tested by the author. To support another provider, register a custom provider from an extension, or fork the package and submit a PR.

Add a custom provider

See examples/custom-provider.ts for a self-contained extension that implements and registers a provider. Copy it into ~/.pi/agent/extensions/, then adapt the endpoint, credentials, response shape, and labels.

pi.events.on("pi-usage-hub:ready", (hub) => hub.register(myProvider));
pi.events.emit("pi-usage-hub:register", myProvider);
pi.events.emit("pi-usage-hub:unregister", { key: "my-relay" });

Pull API

The hub caches results for 60 seconds and deduplicates concurrent requests. It never pushes footer text: consumers start refreshes without blocking lifecycle events, read the cached summary, and re-render when notified.

API Role
pi-usage-hub:ready Provides the hub; also emitted on session_start
hub.refresh({ model?, force? }) Refreshes the matching provider and returns its summary
hub.getSummary(model?) Synchronously reads the cached one-line summary
pi-usage-hub:updated Signals { key, summary } after a cache update

Footer example

footer integration

type UsageHub = {
  getSummary(model?: { provider?: string }): string | null;
  refresh(opts?: {
    model?: { provider?: string };
    force?: boolean;
  }): Promise<string | null>;
};

let usageHub: UsageHub | null = null;
let requestRender: (() => void) | null = null;

const offReady = pi.events.on("pi-usage-hub:ready", (hub: UsageHub) => {
  usageHub = hub;
  requestRender?.();
});

const offUpdated = pi.events.on("pi-usage-hub:updated", () => {
  requestRender?.();
});

// Pi awaits lifecycle handlers; refresh in the background and re-render on pi-usage-hub:updated.
pi.on("session_start", (_event, ctx) => {
  void usageHub?.refresh({ model: ctx.model, force: true });
});
pi.on("model_select", (event) => {
  void usageHub?.refresh({ model: event.model, force: true });
});
pi.on("agent_end", (_event, ctx) => {
  void usageHub?.refresh({ model: ctx.model, force: true });
});

// Inside footer render():
// const usageText = usageHub?.getSummary(ctx.model);
// "XAI 87% · ↻ 3d 16h / M48%"

pi.on("session_shutdown", async () => {
  offReady();
  offUpdated();
  usageHub = null;
});

License

MIT