Provider usage¶
This page describes provider usage reporting and usage-limit behavior.
Subscription Usage¶
Subscription usage is a machine-local view of provider allowance windows — for example, the remaining share of a session or weekly plan window. It is separate from per-agent token usage and from usage-limit auto-disable: collecting a low observation does not itself disable routing.
Collection is on by default and controlled by the durable
llm_provider.usage_metrics.enabled preference:
llm_provider:
usage_metrics:
enabled: true
indicator:
enabled: true
default: { below_remaining_percent: 20 }
weekly_all: always
providers:
muse:
windows:
session: never
Claude, Codex, Grok, Muse Code, and Antigravity currently ship collectors. Claude can
also persist fenced rate-limit events from its normal stream; Codex, Grok, Muse, and agy
are probe-only. Muse's probe is free: it reads the muse serve host's usage through an
echo-provider session, so it makes no model call and spends no tokens. Antigravity's
probe is likewise free: it runs agy -p /usage in plan/sandbox print mode
(agy >= 1.1.11), which answers without starting a model turn. Its four windows —
Gemini weekly and 5-hour plus Claude/GPT weekly and 5-hour — are model_family scoped
to gemini and 3p. Other provider plugins remain fully usable when they do not
implement usage hooks. Per-provider collection can be disabled with
llm_provider.usage_metrics.providers.<name>.enabled: false; routing-disabled providers
still collect when otherwise eligible because their reset information remains useful.
sase's TUI compact usage-window indicator has separate display policy under
llm_provider.usage_metrics.indicator. Collection controls whether SASE probes and
records provider usage; indicator policy only chooses which already-observed windows
appear in the application header. The default shows every positively classified weekly
all-model window (including Muse's weekly window) and any other observed window whose
remaining capacity is strictly below 20%. Claude's observed weekly
weekly:claude-fable-5 window has no bundled entry, so the generic threshold governs it
and the header shows it only when it runs low. Muse's 5-hour session window is hidden
from the header by default (indicator.providers.muse.windows.session: never) but
remains in sase usage list and Providers · Usage. Antigravity's gemini-weekly window
is treated as its weekly anchor under weekly_all and always shows; its gemini-5h,
3p-weekly, and 3p-5h windows follow the generic 20% threshold. Use always,
never, or {below_remaining_percent: N} policies. Exact provider window keys are
stable selectors and can be found in sase usage list --json at windows[].key;
shortened labels in the header are not configuration selectors. Set the exact Fable key
to always to restore always-visible behavior, to never to hide it even when low, or
to a threshold of its own. Invalid display overrides are reported and ignored at that
override while unrelated collection settings and valid provider/window policies keep
working. Config changes are picked up by the normal sase's TUI usage refresh path even
when no provider writes a new usage cache file.
Use sase usage or sase usage list to inspect the cache without provider I/O:
sase usage
sase usage list -p codex --verbose
sase usage list --json
Use sase usage refresh to submit or join bounded durable probe work. Foreground mode
waits for the operations and then prints the refreshed cache; --background returns the
submission receipt immediately. Provider filters are repeatable. --plain provides
stable line-oriented text, while redirected output also becomes plain automatically.
sase's TUI exposes the same cache from Launch Control: press u, or choose Open
Providers · Usage from the command palette. The modal never probes on first paint.
Press its own u to update, close it without cancelling durable work, and reopen to
reattach. The scheduler runs due refreshes inline on its 60-second usage routine.
sase's TUI independently requests due work after its first paint and then every 60
seconds while it remains open, but only when the scheduler does not own collection;
user-triggered refreshes still submit visible procs either way. Per-provider coalescing
makes concurrent scheduler, sase's TUI, CLI, and limit-event requests join the same live
probe.
Background refreshes, and sase usage refresh without -p, only probe eligible
providers: registered providers that are not hidden from model pickers, ship a probe
collector, have a resolvable CLI, and are either referenced by the default model, an
epic-lander model, or a built-in or custom model alias, or explicitly enabled with
llm_provider.usage_metrics.providers.<name>.enabled: true. The CLI check resolves the
executable the same way the launcher does, so Codex counts as ready when it is found
through SASE_CODEX_PATH, PATH, or $NVM_BIN/codex.
Each provider summary reports remaining capacity, scope, freshness, and collection status. Details show every currently retained allowance window with its reset, age, applicability, state, and source; they are current state, not a history of every sample. The cache can therefore distinguish no observation, stale data, unsupported collection, authentication failure, and a real low-capacity window rather than collapsing them into one percentage.
Provider summaries also include collector health when SASE has attempted a probe for the
provider's current account generation. Collector health describes the probe pipeline,
not the freshness of cached allowance windows: passive observations can keep windows
fresh, but they do not reset a broken probe streak. ok means the latest probe attempt
succeeded, degraded means one or two consecutive probe failures, and failing means
three or more consecutive failures. A failing collector surfaces with the streak count,
the first failure time when known, and the last successful probe time when known.
vendor_drift is the reason code used when a provider CLI rejects the request shape
SASE sends, such as an unknown flag, invalid JSON-RPC params, an unsupported method, or
an ACP method-not-found response. A fallback strategy that recovers from drift records
an ok observation with a bounded diagnostic naming the failed primary strategy and the
strategy that recovered. Collector health and diagnostics are display and
troubleshooting signals only; they never disable providers, change routing eligibility,
or alter round-robin/provider-priority decisions.
Grok's included-allowance billing response may omit creditUsagePercent and the used
/ monthlyLimit amounts after a weekly or monthly reset, leaving a unified
currentPeriod with isUnifiedBillingUser: true. SASE treats that verified shape as
zero used. Ambiguous or invalid billing payloads remain collection errors, and the usage
store keeps the previous window until a later successful probe. Recover through the
normal refresh path; do not edit the usage cache by hand:
sase usage refresh -p grok --json
sase usage list -p grok --json
Configuration controls the idle and hot refresh cadences (each at least 60 seconds, with
the hot cadence capped at the idle one; automatic refreshes never run faster than a
provider's polling floor) and warning/critical thresholds as percentages used; UI copy
converts those to percentage left. See
llm_provider.usage_metrics
and the sase usage flags.
Usage-Limit Auto-Disable¶
Usage-limit auto-disable classifies provider errors that mean an account or plan limit
has been exhausted, then writes a temporary provider disable with
source: "usage_limit". It uses the same machine-wide state file and Launch Control
surfaces as manual provider disables, so expiry, self-cleaning, alias routing, direct
provider failures, and early clearing all follow
Temporary Provider Disables.
Provider plugins supply conservative built-in patterns through
llm_default_usage_limit_config(). User configuration lives under
llm_provider.usage_limit:
enabledturns classification on or off globally.disable_secondsis the 24-hour fallback duration used when no reset hint is honored.min_disable_secondsandmax_disable_secondsclamp only provider-reported reset hints, not the administrator-chosen fallback duration.honor_reset_hintallows a provider-reported reset time to choose the expiry, with a small grace buffer of 60 seconds. See Reset-hint forms for what it parses.notifycontrols the notification created for a new automatic disable window.relaunchandrelaunch_limitcontrol whether a hard disable submits a durable drain that relaunches the agents it stranded and how many it moves at most. See Draining a Disabled Provider.providers.<provider>.patternsadds positive provider-specific substrings.providers.<provider>.exclude_patternsadds suppressing substrings for near misses such as "approaching your usage limit".providers.<provider>.replace_patterns: truemakes the configuredpatternslist a literal replacement for built-ins;patterns: []intentionally disables matching for that provider.providers.<provider>.disable_secondsand.honor_reset_hintoverride the global duration/reset policy for that provider;nullinherits the global value.grokships a non-null built-indisable_secondsof 48h because Grok Build reports no reset instant and meters usage against a weekly pool.
Detection is provider-scoped. When the failed execution provider is known, SASE tests
only that provider's usage-limit config; it scans other provider configs only for older
or ambiguous paths that genuinely lack execution-provider provenance. A positive
usage-limit match takes precedence over retry for that provider, so the failing attempt
is not retried against the same disabled provider. A plain transient 429, transport
failure, or model-capacity error that does not match the provider's usage-limit patterns
continues through Retry and Fallback.
Automatic writes are first-window only. If any active disable already exists for that provider, the detector leaves its source, creation time, and expiry unchanged and does not emit another notification. After the record expires or is cleared from Launch Control, a later matching failure may create a new window. Fallback may proceed only to a different enabled provider; it cannot silently route back to the disabled provider.
Reset-Hint Forms¶
When honor_reset_hint is on, SASE tries to read an expiry out of the provider's error
text. Five forms are attempted, in this priority order:
| # | Form | Example |
|---|---|---|
| 1 | ISO-ish absolute timestamp | resets at 2026-08-18 09:00 |
| 2 | Month-name absolute date | resets Aug 18, 2026 9am (America/New_York); weekly-limit resets Aug 22, 8pm (America/New_York) |
| 3 | Clock time with explicit zone | resets at 8pm (UTC) |
| 4 | Bare clock time | resets at 8pm |
| 5 | Relative duration | try again in 2 hours |
Form 1 accepts an optional Z, UTC, or ±HH:MM marker. Forms 1–4 share one keyword
anchor: reset, resets, or try again, followed by an optional at/on. Form 5
needs the keyword to end in in (resets in 90m, try again in 2 hours). A date or
time must follow the keyword immediately, so incidental prose such as "connection reset
by peer" cannot match. Claude Code's seven_day formatter emits a compact meridiem
(8pm, not 8 pm) and omits :00 when minutes are zero.
Parsing commits to the first form whose keyword matches; it does not fall through to
a lower-priority form when that form then fails to resolve. That is why forms 3 and 4
are listed separately: resets at 8pm (Not/AZone) matches form 3, and an unrecognized
zone name there is treated as a failed parse rather than silently reinterpreted as the
bare form 4. Once a usage-limit pattern has already matched, if none of those keyword
forms match, SASE also scans for an unanchored month-name or ISO-ish timestamp so a date
without resets/try again can still set the expiry.
Forms carrying no zone marker — form 1 without a marker, form 2 without a parenthesized
zone, and form 4 — resolve through the configured SASE timezone:. Setting that to
something other than the host's zone will skew those parses.
Any failed or ambiguous parse falls back to disable_seconds. Reading a hint is an
optimization, never a gate: it cannot block or delay the disable.
Draining a Disabled Provider¶
A hard disable stops new launches from landing on a provider; draining goes further
and relaunches the agents that provider already stranded — the ones that were
STARTING, RUNNING, or WAITING on it when the disable landed, plus rows that failed
on it just before the disable. sase.agent._drain_selection selects candidates from one
list_all_agents() snapshot:
- Live rows in
STARTING,RUNNING, orWAITINGon the disabled provider. FAILEDrows whosedone.finished_atis at or afterdisable.created_at - 300sand whose recordeddone.errormatches that provider's own usage-limit pattern throughdetect_usage_limit()— the same matcher that caused the disable in the first place. A manual disable therefore drains a recently-failed row only when the operator disabled the provider because they watched agents fail on it.
Effective provider is agent_meta.json's exec_llm_provider when present, else the
listed llm_provider — a row rerouted through SASE_LLM_EXEC_PROVIDER is selected by
what actually ran, not by its display provider.
Each candidate is replanned exactly like sase agent restart, then its rewritten
prompt's route is classified through plan_launch_units(): if every launch unit is
blocked, the agent is stranded and reported, never guessed onto a substitute model.
Otherwise the first unit's resolved candidate — almost always chosen by ordinary alias
resolution routing around the disabled provider — is the reroute destination. A
prompt pinned to a direct provider/model spelling has nowhere else to go and is always
stranded; only a size or custom alias can reroute.
Never drained, and why:
- Monitor rows (
RunningAgentInfo.is_monitor) supervise a shell command, not provider quota; killing one kills the monitored command instead of freeing anything. QUESTION/ANSWEREDrows hold a pending user interaction that a restart would destroy.- The calling agent —
sase agent drainrun from inside an agent never drains its own caller.
The real cost: like sase agent restart, a drain's execute_agent_restart() deletes
the previous run's artifacts before relaunching. Any in-flight progress on a RUNNING
row is lost; the chat transcript under ~/.sase/chats survives.
The llm_provider.usage_limit.relaunch / relaunch_limit config fields (above) control
whether and how much a usage-limit hard disable drains automatically, as does sase's TUI
Launch Control
automatic provider drain.
sase agent drain <provider> is the always-available manual escape hatch: it previews
with --dry-run, refuses a provider with no active hard disable (exit 2 for
nothing_to_drain, except an automatic request records that empty result as a
successful no-op), and confirms before discarding live progress unless -y/--yes or
-j/--json is given. -m/--model is the way to move an agent the plan would
otherwise report stranded — pointing the whole drain at a reachable model turns every
moved agent into an ordinary reroute. -l/--limit caps how many agents move at once;
anything dropped by the limit is reported, never silently skipped.
Automatic usage-limit drains send one notification for the disable window. The drain
notes report completed relaunches, failed replacement moves, and rows left alone; the
durable proc output has the complete JSON envelope. Inspect a bad drain with
sase proc show <proc-id> --all-lines --output-only and look at each result's error,
recovery_dir, and recovery_prompt fields.
Restart recovery bundles live under ~/.sase/restarts/<timestamp>-<agent>/. For a
failed forced-reuse restart, open the saved rewritten.md prompt from that bundle in
sase's TUI and relaunch through the reviewed launch flow so name reuse, bead context,
session or clan membership, and scoped authorization are reconstructed. Do not recover
forced reuse by running a bare sase run "$(cat rewritten.md)"; execution.md is
retained for audit of the already-prepared launch text, not as a privileged replay path.
Related¶
- Providers and models — the provider integration overview.
- Environment variables — provider-specific variables.
_[project]: A sase project is a named unit of work registered with SASE. _[workspace]: A sase workspace is a numbered clone of a project's primary repo, managed by the workspace store and tracked in that project's registry.json. _[agent]: A sase agent is an agent session or a single agent that does not belong to a session. _[prompt]: A prompt is the text SASE hands to a provider to start an agent turn. _[macro]: A macro is a reusable prompt triggered with #name in agent prompts. _[Patch]: A Patch is SASE's local unit of change. _[bead]: A bead is one tracked work item in SASE's git-native issue tracker. _[plan]: A plan is a persisted, approved artifact recording the intent behind agent work. _[TUI]: The TUI is SASE's terminal interface for running agents and reviewing results. _[epic]: An epic is an executable multi-phase plan run with sase bead work. _[gate]: A sase gate is a durable, command-backed request for one user decision, created when work must pause for the user. _[monitor]: A sase monitor is a monitor turn that runs one long command under a detached supervisor, so the command outlives the agent that started it. *[stitch]: A stitch is the lightweight ordered change record inside a Patch's STITCHES: section.