@marckrenn/pi-sub-core
v1.3.0
Published
Shared usage data core for pi extensions
Readme
sub-core
Shared usage data core for pi extensions. Sub-core owns fetching, caching, provider selection, and emits usage updates via pi.events for the wider sub-* ecosystem (UI and non-UI clients).
Overview
- Fetches usage + status data from providers
- Deduplicates requests via shared cache/lock
- Emits updates for display-focused extensions (e.g.
sub-bar) and non-UI tooling extensions - Supports Antigravity usage via auth.json (
google-antigravity)
Installation
Install via the pi package manager (recommended):
pi install npm:@marckrenn/pi-sub-coreUse -l to install into project settings instead of global:
pi install -l npm:@marckrenn/pi-sub-coreFor a UI, also install a display extension like sub-bar from the same repo (see the root README for the full setup).
Manual install (local development):
git clone https://github.com/marckrenn/pi-sub.git
ln -s /path/to/pi-sub/packages/sub-core ~/.pi/agent/extensions/sub-coreAlternative (no symlink): add it to ~/.pi/agent/settings.json:
{
"extensions": ["/path/to/pi-sub/packages/sub-core/index.ts"]
}Tool Access
Tool registration is gated by tools in ~/.pi/agent/pi-sub-core-settings.json.
By default, both tools are off. To enable them, set:
{
"tools": {
"usageTool": true,
"allUsageTool": true
}
}Then run /reload (tool registration only happens on load). You can also toggle these in /sub-core:settings → Tool Settings.
When enabled, sub-core registers tools to expose usage snapshots to Pi:
sub_get_usage/get_current_usage– refreshes usage (forced by default) and returns{ provider, usage }.sub_get_all_usage/get_all_usage– refreshes and returns all enabled provider entries (auto-enabled providers require credentials).
Settings
Use sub-core:settings to configure shared provider settings plus Usage Refresh Settings and Status Refresh Settings. Provider enablement supports auto (default), on, and off — auto enables a provider only when credentials are detected.
Usage refresh controls cache/usage updates, while status refresh controls incident polling (you can keep status on a slower interval). The Minimum Refresh Interval caps how often refresh triggers can fetch new data even if you refresh every turn.
Antigravity usage requires an OAuth token in ~/.pi/agent/auth.json under the google-antigravity key.
Anthropic extra usage formatting is controlled in Provider Settings (currency symbol + decimal separator).
Settings are stored in ~/.pi/agent/pi-sub-core-settings.json (migrated from the legacy extension settings.json when present; the legacy file is removed after a successful migration).
Settings migrations: settings are merged with defaults on load, but renames/removals are not migrated automatically. When adding new settings or changing schema, update the defaults/merge logic and provide a migration (or instruct users to reset pi-sub-core-settings.json).
Cache
Sub-core stores a shared cache and lock file:
~/.pi/agent/cache/sub-core/cache.json~/.pi/agent/cache/sub-core/cache.lock
Legacy cache files next to the extension entry or in the agent root are migrated to the cache directory and removed on first run.
Security notes
- Keep
~/.pi/agent/auth.jsonreadable only by your user (e.g.chmod 600 ~/.pi/agent/auth.json). - Avoid logging token-bearing headers or auth config when troubleshooting provider calls.
Provider comparison
| Provider | Usage Data | Status Page | Notes | |----------|-----------|-------------|-------| | Anthropic (Claude) | 5h/Week windows, extra usage | ✅ | Extra usage on/off state | | GitHub Copilot | Monthly quota, requests | ✅ | Request multiplier support | | Google Gemini | Pro/Flash quotas | ✅ | Aggregated by model family | | Antigravity | Model quotas | ✅ | Sandbox Cloud Code Assist quotas (tested) | | OpenAI Codex | Primary/secondary windows | ✅ | Credits not yet supported (PRs welcome!) | | AWS Kiro | Credits | - | Credits not yet supported (PRs welcome!) | | z.ai | Tokens/monthly limits | - | API quota limits |
Development
Packaging notes (pi install compatibility)
Pi packages use a pi field in package.json plus the pi-package keyword for discoverability. This repo already declares pi.extensions, so you can install via:
pi install npm:@marckrenn/pi-sub-coreManual paths/symlinks still work for local development as documented above.
Tested providers
Tested so far: Anthropic (Claude), OpenAI Codex, GitHub Copilot. Other providers are implemented but not yet verified in production.
Adding a Provider
You need to update both sub-core (fetch layer) and sub-bar (display layer).
Feature placement (core vs UI)
- sub-core: fetching, caching, provider detection/selection, status polling, tools/events, and shared settings.
- sub-bar: formatting, widget layout, UI-only toggles, and display-specific behavior.
- sub-shared: shared types/constants for anything referenced by both layers.
See the root README “Developer guide” for the decision checklist and examples.
sub-core (fetch + status)
- Add provider name to
src/types.ts(PROVIDERS,ProviderName). - Implement fetcher in
src/providers/impl/<provider>.ts. - Register provider in
src/providers/registry.ts. - Add detection + status config in
src/providers/metadata.ts. - Add provider settings defaults in
src/settings-types.ts.
sub-bar (display + UI)
- Add provider name to
src/types.ts. - Add display rules + labels in
src/providers/metadata.ts. - Add window visibility in
src/providers/windows.ts. - Add extras in
src/providers/extras.ts(if needed). - Add settings UI + defaults in
src/providers/settings.tsandsrc/settings-types.ts.
Events (public contract)
Sub-core uses pi.events as an in-process pub/sub bus. Any sub-* extension can subscribe to updates (UI or headless). Sub-core is the source of truth for provider selection and refresh behavior; clients observe state and optionally request changes.
Broadcasts
sub-core:ready→{ state, settings }(first load)sub-core:update-current→{ state }(cache hit or fresh fetch)sub-core:update-all→{ state }(cached entries + current provider)sub-core:settings:updated→{ settings }
update-current state is { provider, usage }.
update-all state is { provider, entries }, where entries are cached provider snapshots.
Requests (pull current state)
sub-core:request→{ reply, includeSettings? }sub-core:request→{ type: "entries", reply, force? }(bulk usage entries)
The reply callback receives { state } or { entries } immediately if available.
Actions (mutate core state)
sub-core:settings:patch→{ patch }(updates refresh interval/provider settings and persists)sub-core:action→{ type: "refresh" | "cycleProvider", force? }
After an action, sub-core emits sub-core:update-current with the new state.
Credits
- Hannes Januschka (barts, @hjanuschka)
- Peter Steinberger (CodexBar, @steipete)
Status
Active. Used by sub-bar for display.
