Summary
PromptFuel currently models quota usage as a small fixed set of named windows. That was enough for the original Claude/Codex quota surfaces, but it does not scale to newer plan mechanics such as usage credits, extra messages, included-vs-paid usage, monthly pools, or provider-specific tool pools.
Introduce a general UsagePool abstraction that can represent rolling windows, fixed windows, credit balances, included plan usage, paid overage usage, and approximate message/usage pools without hard-coding each provider's current quota shape into every layer.
Current behavior
Quota state is modeled around fixed fields such as fiveHour, sevenDay, and sevenDayOpus.
Several layers know about those specific windows directly, including merge behavior, reset planning, dashboard window keys, snapshot serialization, and status formatting.
This makes it difficult to support:
- Claude usage credits.
- Codex extra messages or add-on credits.
- Monthly or weekly windows beyond the current hardcoded windows.
- Per-tool pools such as Claude Code, Claude chat, Codex CLI, ChatGPT, or API usage.
- Paid-overage-active states.
- Included usage versus extra paid usage.
- Approximate usage when exact limits are unavailable.
Desired behavior
PromptFuel should have a provider-neutral quota model where each quota/credit/allowance surface is represented as a UsagePool.
The existing 5h/7d/Opus windows should continue to work, but they should become specific pool instances rather than hardcoded first-class fields throughout the architecture.
The model should allow future support for warning users before they enter paid overage or start consuming extra credits.
Requirements
-
Add a provider-neutral UsagePool model or equivalent.
-
Support at least these pool concepts:
- rolling window
- fixed window
- credit balance
- allowance
-
Support at least these units:
- percent
- tokens
- messages
- requests
- USD or credits
-
Represent whether a pool is included in the plan or extra/paid usage.
-
Represent overage policy:
- block
- spill to another pool
- pay per use
-
Represent approximate usage when exact accounting is unavailable.
-
Represent derived states such as:
- ok
- approaching limit
- at limit
- overage active
- unknown
-
Preserve existing Claude/Codex 5h/7d/Opus behavior.
-
Derive any legacy fields needed for compatibility instead of breaking current display/status behavior all at once.
-
Keep token/secret handling unchanged.
-
Do not persist raw prompts, raw provider responses, credentials, or tokens.
Non-goals / constraints
- Do not implement a full paid-overage billing estimator in the first pass unless it naturally falls out of the model.
- Do not remove existing dashboard/status behavior until equivalent pool-rendering behavior exists.
- Do not hardcode only Claude usage credits and Codex extra messages; the abstraction should be provider-neutral.
- Do not modify CHANGELOG unless this is part of an explicit release-prep task.
- Do not change pricing math as part of this issue except where needed to represent overage policy metadata.
- Do not create provider-specific one-off fields for every new quota type.
Suggested implementation
A possible minimal shape:
type PoolKind = 'rollingWindow' | 'fixedWindow' | 'creditBalance' | 'allowance';
type UsageUnit = 'percent' | 'tokens' | 'messages' | 'requests' | 'usd';
type UsageLevel = 'ok' | 'approaching' | 'atLimit' | 'overageActive' | 'unknown';
interface UsagePool {
id: string;
provider: string;
toolSurface?: string;
kind: PoolKind;
window?: {
durationSeconds?: number;
resetsAtEpochSeconds?: number;
rolling?: boolean;
};
unit: UsageUnit;
used?: number;
limit?: number;
approximate?: boolean;
includedInPlan: boolean;
overage?: {
policy: 'block' | 'spillToPool' | 'payPerUse';
spillPoolId?: string;
ratePerUnitUsd?: number;
};
balance?: {
remaining: number;
currency: 'usd' | 'credits';
topUpEpochMs?: number;
};
sourceKind?: QuotaSourceKind;
sourceUpdatedEpochMs?: number;
level: UsageLevel;
}
Suggested phase split:
- Add
UsagePool[] while deriving existing legacy fields from pools.
- Convert merge/reset/status/dashboard internals to operate per pool.
- Add pool rendering for existing 5h/7d/Opus windows.
- Add approaching-limit state and warning behavior.
- Add optional credit/overage support through settings or manual import.
Acceptance criteria
Summary
PromptFuel currently models quota usage as a small fixed set of named windows. That was enough for the original Claude/Codex quota surfaces, but it does not scale to newer plan mechanics such as usage credits, extra messages, included-vs-paid usage, monthly pools, or provider-specific tool pools.
Introduce a general
UsagePoolabstraction that can represent rolling windows, fixed windows, credit balances, included plan usage, paid overage usage, and approximate message/usage pools without hard-coding each provider's current quota shape into every layer.Current behavior
Quota state is modeled around fixed fields such as
fiveHour,sevenDay, andsevenDayOpus.Several layers know about those specific windows directly, including merge behavior, reset planning, dashboard window keys, snapshot serialization, and status formatting.
This makes it difficult to support:
Desired behavior
PromptFuel should have a provider-neutral quota model where each quota/credit/allowance surface is represented as a
UsagePool.The existing 5h/7d/Opus windows should continue to work, but they should become specific pool instances rather than hardcoded first-class fields throughout the architecture.
The model should allow future support for warning users before they enter paid overage or start consuming extra credits.
Requirements
Add a provider-neutral
UsagePoolmodel or equivalent.Support at least these pool concepts:
Support at least these units:
Represent whether a pool is included in the plan or extra/paid usage.
Represent overage policy:
Represent approximate usage when exact accounting is unavailable.
Represent derived states such as:
Preserve existing Claude/Codex 5h/7d/Opus behavior.
Derive any legacy fields needed for compatibility instead of breaking current display/status behavior all at once.
Keep token/secret handling unchanged.
Do not persist raw prompts, raw provider responses, credentials, or tokens.
Non-goals / constraints
Suggested implementation
A possible minimal shape:
Suggested phase split:
UsagePool[]while deriving existing legacy fields from pools.Acceptance criteria
approaching,atLimit, andoverageActivestates can be derived without provider-specific branching.