pi-balance

Pi extension that displays provider account balance in the status bar.

Packages

Package details

extension

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

$ pi install npm:pi-balance
Package
pi-balance
Version
1.0.2
Published
May 25, 2026
Downloads
1,414/mo · 16/wk
Author
rokiy
License
MIT
Types
extension
Size
196.7 KB
Dependencies
0 dependencies · 2 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/index.js"
  ],
  "image": "https://img.dog/file/1779542581467_mzRI9XShNB2pFCVDlx1f8.webp"
}

Security note

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

README


📋 Features

pi-balance is an extension for the pi coding agent that automatically fetches and displays your AI provider's API credit balance in the pi status bar.

  • Auto-detects your currently active model provider
  • Event-driven refresh — balance updates automatically after each conversation (with delta display ▲▼)
  • Live updates on provider/model switch
  • Multi-provider support — DeepSeek, Moonshot/Kimi, OpenRouter, Sub2Api, OpenAI Codex (and compatible APIs)
  • Zero configuration for balance APIs — supported balance APIs work from existing model headers
  • Graceful fallback — quietly hides when balance info is unavailable
  • i18n support — English and Simplified Chinese, with /balance lang <zh-CN|en> command

📦 Installation

Option 1: Install from npm (Recommended)

pi install npm:pi-balance

Option 2: Install from GitHub

pi install git:github.com/DragonYH/pi-balance

Option 3: Local Development

git clone https://github.com/DragonYH/pi-balance.git
cd pi-balance
npm install
npm run build
pi install ./

Verify Installation

Restart pi. You should see the balance indicator appear in the status bar once you connect to a supported provider.

🔌 Supported Providers

Provider Balance Endpoint Display
DeepSeek /user/balance ¥ (CNY) balance
Moonshot / Kimi /v1/users/me/balance ¥ (CNY) available balance
Sub2Api /usage $ (USD) remaining balance
Compatible APIs /usage, /v1/usage $ (USD) remaining balance
OpenAI Codex ChatGPT Codex usage API / codex app-server 5-hour and weekly usage remaining
OpenRouter /v1/credits $ (USD) remaining credits

The extension automatically detects which provider you're using based on your current model configuration — no manual setup required.

🚀 Usage

Once installed, pi-balance works completely automatically:

  1. On session start — it fetches your balance immediately
  2. On model switch — it re-fetches for the new provider
  3. After each conversation (agent_end) — automatically refreshes and shows balance delta (▲▼)

The balance is displayed in the status bar at the bottom of your pi terminal:

DeepSeek: ¥49.87

If the extension cannot determine your balance (e.g., unsupported provider or network issue), the status bar entry is gracefully hidden.

/balance Command

Run /balance to open an interactive configuration menu. You can:

  • View support status for configured providers
  • Expand/collapse providers to toggle display and extra options
  • Enable/disable Sub2Api sub-providers inline (with auto-discovery)
  • Toggle Codex CLI fallback on/off
  • Refresh the current status immediately

You can also use command arguments directly:

/balance status
/balance refresh
/balance enable deepseek
/balance disable moonshot
/balance toggle codex
/balance toggle openrouter
/balance toggle sub2api
/balance sub2api               # Open Sub2Api sub-provider menu
/balance sub2api rescan         # Re-scan for new Sub2Api providers
/balance lang zh-CN             # Switch to Simplified Chinese
/balance lang en                # Switch to English

Configuration Notes

  • Provider display toggles are saved by the /balance menu and apply on the next refresh.
  • Custom Sub2Api providers are discovered from your pi model configuration (~/.pi/agent/models.json) and can be enabled/disabled individually from the main menu or /balance sub2api. Use /balance sub2api rescan after changing model configuration.
  • OpenAI Codex usage is shown only while the active model provider is openai-codex. The extension first reuses pi's Codex subscription auth headers and can fall back to codex app-server --listen stdio:// when available; the CLI fallback can be toggled in the /balance menu.
  • The menu caches support states intelligently: expanding/collapsing providers is instant (no recomputation), while config changes trigger automatic refresh.
  • Network requests time out quickly and failures are hidden from the status bar instead of interrupting your session.

🧠 How It Works

┌─────────────────────────────────────────────────────────────┐
│  pi Coding Agent                                            │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                                                       │  │
│  │  [Chat Interface]                                     │  │
│  │                                                       │  │
│  ├───────────────────────────────────────────────────────┤  │
│  │  Status Bar:  DeepSeek: ¥49.87     ◉ Connected        │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌─ Extension: pi-balance ───────────────────────────────┐  │
│  │  session_start  ──►  fetchBalance()  ──►  setStatus() │  │
│  │  model_select   ──►  fetchBalance()  ──►  setStatus() │  │
│  │  agent_end     ────►  refreshBalance(showDelta)        │  │
│  └────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

Events Handled

  • session_start — initial balance fetch when a session begins
  • model_select — re-fetch when you switch models/providers
  • agent_end — refresh balance after each conversation, showing delta (▲▼)
  • session_shutdown — cleanup and clear status

🏗️ Project Structure

pi-balance/
├── src/
│   ├── index.ts                  # Entry point, commands, lifecycle
│   ├── types.ts                   # Type definitions and constants
│   ├── config.ts                  # Config load/persist/toggle
│   ├── utils.ts                   # Helpers (fetch, JSON, type guards)
│   ├── menu.ts                    # Dynamic menu builder with caching
│   └── providers/
│       ├── types.ts               # BalanceProvider interface
│       ├── registry.ts            # Singleton provider registry
│       ├── deepseek.ts            # DeepSeek provider
│       ├── moonshot.ts            # Moonshot/Kimi provider
│       ├── openrouter.ts          # OpenRouter provider
│       ├── sub2api.ts             # Sub2Api + auto-discovery
│       └── codex.ts               # OpenAI Codex + CLI fallback
│   └── i18n/
│       ├── index.ts              # t() function + language detection
│       ├── zh-CN.ts              # Chinese translations
│       └── en.ts                 # English translations
├── tests/
│   └── index.test.ts
├── LICENSE                       # MIT license
├── README.md                     # English documentation
├── README.zh-CN.md               # Chinese documentation
├── package.json                  # Node.js and pi package manifest
├── tsconfig.build.json           # Build configuration
└── tsconfig.json                 # TypeScript configuration

🛠️ For Developers

Type-Checking

npm run typecheck

Build

npm run build

Test

npm test

Publish Checklist

This project publishes through GitHub Actions when a version tag is pushed.

Before publishing, verify the package contents:

npm pack --dry-run

Then create and push a tag that matches package.json:

git tag vX.Y.Z
git push origin vX.Y.Z

Before pushing the tag, configure npm Trusted Publishing for this package:

  • Publisher: GitHub Actions
  • Owner: DragonYH
  • Repository: pi-balance
  • Workflow: release.yml
  • Environment: leave empty unless you add one to the workflow.

Adding a New Provider

The extension uses a pluggable provider architecture. To add support for a new provider, create a module in src/providers/ that implements the BalanceProvider interface, then import it in src/index.ts to trigger auto-registration:

// src/providers/yourprovider.ts
import type { BalanceProvider } from "./types.js";
import { registry } from "./registry.js";
import type {
  BalanceResult,
  BalanceConfig,
  FetchContext,
  ProviderSupport,
} from "../types.js";
import { getJson } from "../utils.js";

export const yourProvider: BalanceProvider = {
  key: "yourprovider",
  definition: {
    key: "yourprovider",
    label: "YourProvider",
    color: "#FFD700",
  },

  shouldTry(model, baseUrl) {
    return baseUrl.includes("yourprovider.com");
  },

  async fetchBalance(
    ctx: FetchContext,
    signal?: AbortSignal,
  ): Promise<BalanceResult | undefined> {
    const data = await getJson(`${ctx.baseUrl}/your/endpoint`, ctx.headers, signal);
    const amount = data?.credits_remaining;
    return typeof amount === "number" ? { amount, unit: "$" } : undefined;
  },

  async getSupport(
    ctx: ExtensionContext,
    config: BalanceConfig,
  ): Promise<ProviderSupport> {
    return {
      provider: this.definition,
      configured: true,
      details: ["Configured"],
    };
  },
};

registry.register(yourProvider);

Then add one import in src/index.ts:

import "./providers/yourprovider.js";

That's it — the provider auto-registers, appears in the /balance menu, and participates in balance fetching. No other code changes needed.

📄 License

MIT