---
title: Distribute Sessions Across Accounts
---

# Distribute Sessions Across Accounts

## What it is

**One-paragraph answer:** "Distribute Sessions Across Accounts" is a setting (Settings → Accounts) that spreads new Claude Code sessions across all of your **login** accounts based on how much each has been used, instead of piling every session onto a single active account until it hits its limit. With it on, each new session starts on the account that currently has the most headroom — with a gentle preference for an account whose usage window is about to reset — weighted most toward the **weekly (7-day)** window, since that is the bigger paid-for chunk — so capacity that would otherwise expire unused gets harvested first; each session then stays on its own account; and when one account hits its rate limit, only that account's sessions move elsewhere — there is no synchronized "switch everything at once." If one account gets busy while others sit idle, Omniscio also proactively moves a couple of its sessions to a freer account _before_ they stall, parks a session that keeps bouncing across a fully-maxed pool, splits each account's chip into how many sessions are actively running vs. parked waiting on you (and shows a maxed account's sessions as a muted **"waiting"** instead of a misleading green **"live"**) It is **off by default** since 2026-08-29 (fresh installs run a single account; installs from before that date keep the on-by-default setting they had — turn it on in Settings → Accounts with 2+ login accounts), needs **2+ login accounts** to do anything, and when off, account behavior is exactly the same as it has always been.

### Why it exists

Normally Omniscio funnels every new session onto one "active" account. If you run many sessions in parallel, that one account's 5-hour usage window drains fast, and when it caps, Omniscio flips your whole fleet over to the next account at once. With several accounts, that means you only ever use one window at a time and you get a big synchronized stall at each cap.

Load balancing changes the economics: with 3 login accounts, new sessions fan out across all three, so you get roughly **3× the effective 5-hour window**, each account drains at about a third the rate, and there is no fleet-wide mass switch — caps happen one account at a time and only affect that account's sessions.

The goal is to **use as much of your total capacity as possible before it resets**. Spreading evenly is most of that; the soon-to-reset preference (below) is the rest — it steers real work toward capacity that's about to cycle so less of it expires unused, weighted hardest toward the **weekly (7-day)** window because a whole week's unused budget is the bigger thing to forfeit. It does not manufacture work: with only a couple of sessions running you can't fill every account, and it won't try to.

## Where to find it

### Requirements and where to find it

- **Settings → Accounts**, a toggle labeled **"Distribute Sessions Across Accounts."**
- The toggle only appears when you have **2 or more login (OAuth) accounts**. API-key accounts do not participate in load balancing (they remain a last-resort fallback exactly as before), so a single login account plus an API key still does not show the toggle.
- Default: **off** since 2026-08-29 — fresh installs run a single account; turn it on anytime with 2+ login accounts. Installs from before that date are preserved: a config that never saved the setting keeps the old on behavior, and any explicit choice you made stays exactly as you left it.

## How it behaves

### What it does when ON — five behaviors

1. **Spread at spawn, with a soon-to-reset preference.** When a new session starts, Omniscio picks the **least-loaded** login account that still has capacity (lowest of its 5-hour / 7-day utilization), rather than always using the pinned/active account. On top of that, it gives a **bounded preference to an account whose usage window is about to reset and still has room** — so capacity that's about to reset (and would otherwise go unused) gets harvested first. This runs for **both** windows: the 5-hour window (a small nudge over its final hour) and — weighted **about twice as hard and over roughly three days' runway** — the **weekly (7-day)** window, because the weekly budget is the bigger paid-for chunk and the 5-hour limit throttles how fast you can draw it down, so draining a week's leftover needs a multi-day head start (the runway was widened from one day to three on 2026-07-05, because a single day often wasn't long enough to use up a big weekly balance before it reset). Each preference is **capped** so it can win a close call but never overrides a clearly-fresher account, and both are measured against the _higher_ of the account's 5-hour and 7-day usage, so they never push an account toward its scarcer weekly limit or into an early weekly lockout. (If an account doesn't report a reset time, it simply gets no preference — even spread as before. The weekly harvest has its own off switch: `AMC_DISABLE_LB_SEVEN_DAY_HARVEST=1`.) Omniscio also weighs **how many sessions each account is already running** (the same in-use count the account dropdown chip shows, split there into active + waiting on you): each live session makes its account a little less preferred, so new sessions fan out toward the quieter accounts instead of stacking on one — even when several accounts look equally fresh and the sessions are started minutes apart (not just in a tight burst). That preference is **capped** (after roughly six sessions an account stops looking progressively worse), so it never sends work to an almost-maxed account just because another one is busy — real usage always wins at the extreme. **A hard ceiling stops a pile-up.** That per-session preference only _slows_ how fast one account fills; once an account is the clear favorite on usage it can still absorb a long run of back-to-back sessions (in practice one account was seen climbing to ~20 live sessions while others sat nearly empty). So on top of it, once an account is carrying more than its fair share of live sessions, Omniscio stops handing it new work and fans the next sessions out to other accounts that have room — **unless** the only accounts with room are themselves near their limit, in which case it keeps using the busy-but-fresh account (it never trades an even spread for a spawn onto an almost-maxed account). The ceiling scales with how busy you are, so an even spread is never disturbed; it only engages when one account has genuinely run ahead. It counts sessions that are still spinning up, not just ones already fully started (the same way the near-limit cap below does), so a rapid burst of new sessions can't all pile onto one fresh account before its usage numbers catch up — the gap that used to let one account reach ~14 live sessions while healthy accounts sat idle. (Emergency off switch: `AMC_DISABLE_LB_SESSION_CEILING=1`.) During a sudden burst (e.g. you launch 30 sessions at once, before fresh usage numbers have come back), an additional short-lived "just spawned here" nudge makes the burst fan out evenly instead of all landing on whichever account looked freshest for a split second. **A near-limit account is held to one session at a time.** As a final safety rail, once any account crosses **95% of its weekly (7-day) budget**, Omniscio lets it run only a **single** session at once and sends any additional new session elsewhere — so an account about to exhaust its scarce weekly allowance can't have several sessions pile onto it and cap together. This is stricter than the ceiling above (which only steers _toward_ comfortable accounts and otherwise gives up and uses the busiest); it is the one rule that reliably keeps a nearly-maxed weekly account from absorbing a whole burst. It counts sessions still spinning up (not just fully-started ones), so a rapid burst can't slip past it. If _every_ account is in that state at once, Omniscio still starts the session rather than leaving you stuck. (Emergency off switch: `AMC_DISABLE_LB_HOT_ACCOUNT_CAP=1`.)
2. **Stay put (per-session account affinity).** Each session normally keeps using its own account across turns. Omniscio does **not** force an idle session to follow the global active account on its next message, so a session that started on account B usually keeps using account B. Exceptions: if you _remove_ account B from Omniscio, or if that home account is already carrying well above its fair share while another comfortable login has room, the next respawn can re-home the session instead of piling even more work onto the overloaded account.
3. **Re-spread on cap-out.** When one account hits its rate limit, only **that account's** sessions are affected, and each independently re-picks another account that still has room — instead of dumping them all onto one other account (which would just recreate the pile-up). There is no global account switch and no synchronized cascade. If _every_ account is capped, sessions wait for the soonest reset exactly as they do today, then resume on whichever account recovered.
4. **Proactively drain an over-loaded account before it stalls.** Re-spread (behavior 3) only moves a session _after_ it personally hits a limit — so one account could keep many sessions on it, each capping one at a time over a long stretch, while other accounts sit nearly idle. About every 5 minutes (when fresh usage numbers come in), Omniscio drains an over-loaded account onto one with real room — never more than two sessions per check, and never onto an account that's itself nearly full — in either (or both) of two independent cases per check:
   - **Near its limit** and carrying more than its fair share → it moves a couple of its **running** sessions over before they cap (they are the actual load about to stall).
   - **Far over its fair share by session count**, even while its usage still looks calm → a big pile on one account never trips a rate limit _as a whole_, yet it repeatedly maxes its own 5-hour window and leaves its sessions "waiting" while other accounts idle. Here Omniscio drains **gently**: it re-homes only sessions that can move for free — never one that's actively working, and never one that's waiting on your answer — so nothing in progress is interrupted. The pile evens out over the next few checks as its running sessions finish and become movable, while behavior 1's ceiling keeps new work off it. This calm-pile case now runs on its own each check — it is **no longer skipped** whenever some _other_ account happens to be near its limit (which, with many accounts, was almost always). Before, that meant a calm-but-over-piled account — the exact thing that stranded ~20+ sessions on one account — could sit undrained until it capped on its own.

   (Emergency off switches: `AMC_DISABLE_LB_REBALANCE=1` disables all draining; `AMC_DISABLE_LB_COUNT_REBALANCE=1` disables just the second, count-based case while leaving the near-limit drain on.)

5. **Stop a session from bouncing forever (anti-thrash).** When _every_ account is hot, a single session can ping-pong — run, hit a limit, move, hit a limit, move — every minute or so for hours without ever finishing its turn. After it has been bounced a few times in a 15-minute window without settling, Omniscio **parks it** to wait for the next reset instead of burning another restart, and lets it try again once the pool cools off.

### Seeing it work — the header indicator

When load balancing is on, the **account pill in the top toolbar** (the small
control at the top-right that normally shows one account's usage %) changes to
report the pool instead of a single account:

- A **balance-scale icon followed by a number** — the number is how many of your
  accounts are **currently in use** (running at least one live session right
  now). "In use" counts sessions that are running, starting, stalled, or waiting
  on you; it excludes idle pre-warmed blanks, silent background recipe sessions,
  and **errored (dead) sessions — a session that crashed and is sitting red has
  no running process, so it doesn't count as "live"** (since 2026-06-10; before
  that, a pile of errored sessions could inflate the count). The number matches
  what your sidebar shows.
- The old single-account **percentage is replaced by a small pool-health glyph**:
  a green check means _"your whole pool won't run out before its limits reset,"_
  an amber triangle means _"the pool is projected to run low,"_ and a red ✕ means
  _"almost out / every account is capped."_ This replaces the percentage because
  under load balancing that number was just the pinned account's usage — usually
  your busiest one — so it looked alarming even when ten other accounts had
  plenty of headroom. The glyph is the same verdict shown in the account
  dropdown's forecast row, so the two never disagree. (During the forecast's
  cold-start window, or if you've turned the usage forecast off, the glyph is
  simply omitted and the pill shows just the scale icon + count.)
- Hovering the pill adds a **"Load balancing on · N accounts in use"** line to
  the tooltip, plus the pool-health verdict in words.
- **Opening the dropdown** shows a "Balancing · N in use" line under the Accounts
  header, and each account that's running work gets a chip that **splits its sessions into
  how many are actively running versus parked** — green **"N running · M waiting"**
  (or just **"N running"** when all are running, or **"M waiting"**
  when none are). "Running" means actually streaming tokens right now; "waiting"
  is the rest — parked for your reply, spinning up, or stalled — which burn
  nothing, so a big count next to 0% usage is no longer a mystery. One click
  answers not just _how many_ accounts but _which ones, and how busy each is_. **An account that is at capacity (its 5-hour _or_ weekly window maxed,
  no extra credits) instead shows a single muted "N waiting" chip** — all its
  sessions are stranded: they can't run until the limit resets or they move to a
  freer account. The active + waiting numbers always add up to the same in-use
  total the load balancer uses (account-switch invariant `standing-per-session-load-spreads-spawns`) — only the
  presentation is split. Balancing also **orders the dropdown by which account it would use next** — the active account leads, but once it is at capacity (the same "N waiting" state) it is no longer pinned to the top; it drops to its real position so accounts with room lead.

On a **phone / narrow mobile layout** the mobile account chip (the account control
in the mobile header) shows a **more compact** version: just the **balance-scale
icon, and the icon's own COLOUR is the pool-health verdict** — green when your pool
won't run out before its limits reset, amber when it's projected to run low, red when
it's out of capacity (change of 2026-07-10; this replaced the older separate
green-check / amber-triangle / red-X glyph that used to sit beside the scale). The
accounts-in-use **number was already dropped from the chip face** to save room on the
narrow bar (2026-07-09); it still rides the chip's tooltip/label, and opening the chip
shows the full "Balancing · N accounts in use" line plus the same running/waiting split
chip ("N running · M waiting") on each login account. When there's no verdict yet (a
cold-start window, or the usage forecast is off) the scale is a neutral grey and
highlights in the accent colour while the account menu is open. Mobile and desktop read
the exact same session/forecast state through shared code, so their verdicts can never
disagree — the colour is the same one the desktop pill and the Settings forecast row
show; mobile just carries it on the scale icon itself instead of a separate glyph.

When load balancing is **off**, the pill (and the mobile chip) is exactly as it
was before — the single-account percentage and status dot — with none of the above.

### Seeing it work — inside a session

The header pill is the pool-wide view; each individual session also explains itself,
so an ember/orange session in the sidebar is never a mystery:

- **A parked session shows a pinned banner.** While a session is waiting on a rate
  limit (its **"waiting"** status — ember orange), a persistent
  **"Waiting for a Claude account with available usage — resumes automatically, no action needed"**
  banner sits at the top of that session. It is pinned (not a message that scrolls
  away), clears itself the instant the session resumes, and has nothing to click — the
  wait needs nothing from you.
- **A moved session shows a caption in its log.** When a rate-limited session resumes
  on a **different** account (re-spread on cap-out, or the proactive drain), the message
  log shows a small **"Switched to a Claude account with available usage to keep going"** divider right
  where the turn picked back up — so the failover is visible instead of buried in the
  collapsed activity. A same-account resume (the limit simply cleared, nothing moved)
  shows no caption.
- **The "waiting" state is reserved for a GENUINE pool-wide shortage.** A session only
  turns ember **"waiting"** (and only then does the *"Sessions waiting on account
  capacity"* inbox alert appear) when **every** account is genuinely out of usage. If a
  session briefly bounces off a temporary "slow down" from Anthropic (a burst throttle,
  which can hit an account that still has plenty of usage left) while other accounts have
  room, it stays silent and simply re-routes to a free account — no orange badge, no
  "out of capacity" alert. So that alert firing genuinely means the whole pool is capped,
  not that one account hiccuped. (Safety net: a session somehow stuck for 10+ minutes
  still surfaces so nothing hides forever; emergency revert `AMC_DISABLE_CAPACITY_FLEET_GATE=1`
  restores the old always-surface behavior.)
- **A one-login pile-up warns you on its own (2026-07-27).** If one login ends up carrying a
  large, SUSTAINED pile-up of actively-running sessions while another account still has room,
  AMC raises a single dismissible inbox note ("Your _login_ is carrying _N_ active sessions…")
  so you notice the imbalance instead of catching it by screenshot. It is deliberately rare —
  it needs a genuine, sustained pile-up on a login that is ALSO climbing toward its limit while
  a cooler login sits idle — and it clears itself as the load evens out. Nothing stops working;
  you may just see more rate-limit waiting on that one login until its window resets. This
  warning now fires whenever load balancing is on (it is no longer gated behind the
  in-development capacity-ledger flag). Env revert `AMC_DISABLE_LB_CONCENTRATION_ALERT=1`
  silences just the alert; the underlying metric keeps logging.

### What "pinning / Activate an account" means while it's ON

The manual **Activate** action (clicking an account to make it active) still works and still moves your existing sessions — that is treated as deliberate user intent. But for _new_ spawns, load balancing intentionally ignores the pinned account and spreads instead; the pinned account just becomes the display default. If you want the old "everything on one account" behavior back, turn the toggle off.

### When OFF

Behavior is **byte-for-byte identical to the old single-account model**: new sessions use the pinned/active account, sessions are force-migrated to follow the active account, and a rate limit triggers the normal auto-switch + fleet cascade (governed by the separate "Auto-Switch Account on Rate Limit" setting). Turning load balancing off fully restores this.

### Kill switch

Set the environment variable `AMC_DISABLE_DISTRIBUTE_SESSIONS=1` to force the feature off regardless of the setting (the env kill switch always wins). This is an emergency escape hatch; normal users just use the toggle.

### Relationship to "Auto-Switch Account on Rate Limit"

These are different settings. "Auto-Switch" (when on) moves your _whole_ active account to a fresh one when the active account caps. Load balancing instead keeps sessions distributed and moves only the affected account's sessions. When load balancing is on, the automated global auto-switch is suppressed (so the two don't fight); the manual Activate switch is unaffected.

## For agents

### For agents with repo access — where this lives

- Feature flag + kill switch: [src/main/services/distribute-sessions-flag.ts](../../src/main/services/distribute-sessions-flag.ts) (`isDistributeSessionsEnabled(settings)`, `AMC_DISABLE_DISTRIBUTE_SESSIONS`).
- Setting: `distributeSessionsAcrossAccounts` in `AppSettings` (default **`false`** as of 2026-08-29; was `true` 2026-05-31→2026-08-29) + Zod field in [src/shared/ipc-schemas/update-settings.ts](../../src/shared/ipc-schemas/update-settings.ts); UI toggle in [src/renderer/src/features/settings/sections/accounts/AccountSettings.tsx](../../src/renderer/src/features/settings/sections/accounts/AccountSettings.tsx). Pre-flip installs are preserved by load-save's pre-parse seed (a raw config missing the key persists the old `true`; explicit choices are never rewritten) — the former force-ON one-shot migration is retired. `isDistributeSessionsEnabled` and every UI read-site fall back `?? false`, matching the default.
- Spread-at-spawn picker: `pickLoadBalancedAccount` in [src/shared/account-pool.ts](../../src/shared/account-pool.ts); wired into `pickActiveAccount()` in [src/main/process/process-manager.ts](../../src/main/process/process-manager.ts). Effective load = `max(5h,7d) + standing-session penalty + in-flight penalty − 5h-reset bias − 7d-reset bias`. **Standing per-session penalty:** `min(liveSessions × LOAD_BALANCE_SESSION_STEP, LOAD_BALANCE_SESSION_CAP)` (5/session, cap 30), exact ties broken by fewer live sessions; `liveSessions` comes from `getLiveSessionCountsByAccount()` ([src/main/db/queries-sessions/reads.ts](../../src/main/db/queries-sessions/reads.ts)), which shares `IN_USE_STATUSES` + `isSilentlyHidden` with the header via [src/shared/session-live.ts](../../src/shared/session-live.ts) (the renderer `lib/silent-session.ts` re-exports it) so the picker's count equals the "N live" chips; the call is try/caught (degrades to usage-only on failure). **Per-account live-session ceiling:** above the soft session cap, the picker narrows the ranked set to accounts that are BOTH under `max(LB_SESSION_CEILING_MIN = 8, ceil(totalPoolLive / poolSize) + LB_SESSION_CEILING_SLACK = 2)` live AND comfortable (`primaryScore < LB_COMFORTABLE_PCT = 80`), falling back to the full pool when no comfortable under-ceiling account exists (never blocks a spawn, never routes onto a near-maxed account — preserves the cap's invariant-24 guarantee); the ranking itself is unchanged, only the candidate set is narrowed. The caller passes `sessionCeilingEnabled` from the `AMC_DISABLE_LB_SESSION_CEILING=1` kill switch. Contract invariant 27. **Hot-account 7-day session cap:** ahead of — and feeding — the ceiling narrowing, a login at/above `LB_HOT_ACCOUNT_SEVEN_DAY_PCT = 95` on its 7-day window that already carries (live + in-flight) `≥ LB_HOT_ACCOUNT_SESSION_CAP = 1` session is dropped from the candidate set; the ceiling's `comfortableUnder` then filters this narrowed set rather than the raw pool, and both fall back to the full pool when every account is hot-and-at-cap (never strands). Because 95 > `LB_COMFORTABLE_PCT` (80) a hot account already fails the comfort gate, so this is load-bearing only in the ceiling's "nothing comfortable → use the raw pool" branch. The caller (`pickViaLoadBalancer` in [src/main/process/account-selection.ts](../../src/main/process/account-selection.ts)) passes `hotAccountCapEnabled` from the `AMC_DISABLE_LB_HOT_ACCOUNT_CAP=1` kill switch. Contract invariant 28. **In-flight counter:** transient burst spread ([src/main/process/spawn-load-tracker.ts](../../src/main/process/spawn-load-tracker.ts), 20s TTL). **Soon-to-reset urgency bias (per window):** the shared `resetUrgencyBonus(account, resetMs, horizonMs, cap)` is subtracted once per window — 5-hour (`LOAD_BALANCE_URGENCY_CAP = 15`, `LOAD_BALANCE_URGENCY_HORIZON_MS = 1h`) and 7-day (`LOAD_BALANCE_SEVEN_DAY_URGENCY_CAP = 30`, `LOAD_BALANCE_SEVEN_DAY_URGENCY_HORIZON_MS = 72h` / ~3 days, widened from 24h on 2026-07-05 — weighted 2× over a much longer runway because the weekly budget is the bigger forfeited chunk and 24h often wasn't long enough to drain it before reset; HORIZON is the "harvest harder" lever, the CAP stays put so a burst still fans out). Both use `headroom = 100 − max(5h,7d)` (protects the 7-day budget + avoids an early weekly lockout) and stack when both windows are imminent. Reset distances are `AccountWithUsage.fiveHourResetMs` / `sevenDayResetMs`, computed in `buildAccountsWithUsage` from `usage.{fiveHour,sevenDay}.resetsAt`. The 7-day term is gated by the `sevenDayHarvestEnabled` option from the `AMC_DISABLE_LB_SEVEN_DAY_HARVEST=1` kill switch (5-hour unaffected); the rebalancer (`pickBestAccount`) is NOT a consumer. Contract invariant 22.
- Per-session affinity + cap-out re-spread: [src/main/services/rate-limit-recovery-service.ts](../../src/main/services/rate-limit-recovery-service.ts) (`tryAutoSwitch` no-op under LB; `lb-respawn` per-session trigger; the consume-once exclude-account hint, `markExcludeAccountOnNextSpawn` → [src/main/process/next-spawn-directives.ts](../../src/main/process/next-spawn-directives.ts)). Resume affinity is routed through [src/main/process/spawn-cluster-manager.ts](../../src/main/process/spawn-cluster-manager.ts) + [src/shared/account-pool.ts](../../src/shared/account-pool.ts) (`preferAccountId`), and it now yields to the live-session ceiling when another comfortable account has room.
- **Proactive rebalance** (drain an over-subscribed account before it caps): `rebalanceOverloadedAccounts` in [src/main/services/rate-limit-recovery-service.ts](../../src/main/services/rate-limit-recovery-service.ts), called from `onUsageRefreshed` under LB. Two INDEPENDENT SOURCE triggers via `pickDrainSources`, each draining its OWN source per cycle (HEAT first, then COUNT) through the shared `drainOneSource`: **HEAT** = `utilOf ≥ LB_REBALANCE_HIGH_WATER_PCT` (80) + over fair share → drains RUNNING-first candidates; **COUNT** = `liveCount ≥ LB_REBALANCE_COUNT_RATIO (2) × fairShare` even _below_ the high-water → GENTLE, candidates filtered to non-`running`/`starting` **and** `!hasActionablePending` (the shared predicate `restartSession`'s needs_you guard uses), so no active turn or pending question is ever moved. The COUNT trigger is **NO LONGER gated on `!heatSource`** (2026-07-22): that preemption starved it whenever ANY account was hot — the busy-fleet norm — so a calm, over-piled account sat undrained (the ~27-live active-account pile-up). It now only EXCLUDES the heat account so one account is never drained twice; being restart-free (idle re-point) it adds no kills, so running both per cycle keeps process kills ≤ `LB_REBALANCE_MAX_PER_CYCLE` (heat path only). `LB_REBALANCE_COUNT_RATIO` mirrors `CONCENTRATION_ALERT_RATIO` (kept a local constant to avoid a service import cycle). Bounded by `LB_REBALANCE_MAX_PER_CYCLE`; moves via the `lb-rebalance` trigger + `markExcludeAccountOnNextSpawn`; candidate sessions from `getLiveSessionsForAccount` ([src/main/db/queries-sessions/reads.ts](../../src/main/db/queries-sessions/reads.ts), same filter as `getLiveSessionCountsByAccount`). Kill switches: `AMC_DISABLE_LB_REBALANCE=1` (all draining) / `AMC_DISABLE_LB_COUNT_REBALANCE=1` (the count trigger only). Locked by [tests/unit/db/get-live-sessions-for-account.test.ts](../../tests/unit/db/get-live-sessions-for-account.test.ts) + the `proactive rebalance` block (incl. the `count-concentration drain` sub-block) in [rate-limit-recovery-load-balance.test.ts](../../tests/unit/services/rate-limit-recovery-load-balance.test.ts). Contract invariant 25.
- **Anti-thrash backstop** (park a session bouncing across a saturated pool): `lbRespawnTimestamps` + `LB_RESPAWN_THRASH_MAX` / `LB_RESPAWN_THRASH_WINDOW_MS` in `onLbSessionRateLimited` (same file); contract invariant 26.
- Header indicator (display-only): the desktop toolbar pill [src/renderer/src/components/ui/AccountIndicator.tsx](../../src/renderer/src/components/ui/AccountIndicator.tsx) renders the scale icon + accounts-in-use count + pool-health glyph; the mobile chip [src/renderer/src/components/ui/MobileAccountChip.tsx](../../src/renderer/src/components/ui/MobileAccountChip.tsx) renders a compact **scale icon + pool-health glyph only** — the accounts-in-use count is dropped from the narrow chip face (it stays in the chip's aria-label + the dropdown's "Balancing · N in use" line), and the neutral scale icon turns accent while the account menu is open (2026-07-09; deliberate mobile divergence from the desktop pill). The per-account live count comes from `computeLiveSessionsByAccount` ([src/renderer/src/lib/account-live-sessions.ts](../../src/renderer/src/lib/account-live-sessions.ts), "in use" = `LIVE_STATUSES` minus `ready`/`terminating`/`error` — dead sessions are not load, silent-excluded) and the glyph from `pickForecastGlyph` ([src/renderer/src/lib/forecast-glyph.ts](../../src/renderer/src/lib/forecast-glyph.ts), mirrors `GlobalUsageForecastRow`). The two surfaces share `EMPTY_LIVE_BY_ACCOUNT` (the frozen LB-off subscription guard, in `account-live-sessions.ts`), [`ForecastGlyphIcon`](../../src/renderer/src/components/ui/account/ForecastGlyphIcon.tsx) (glyph→icon), and [`LiveSessionChip`](../../src/renderer/src/components/ui/account/LiveSessionChip.tsx) (the active/waiting split chip — its active count comes from the shared `countStreamingSessionsByAccount`) so they can't drift. Pure reads of session state + the existing usage forecast — no spawn/recovery change. The chip's at-capacity ("waiting") state is decided by `isAccountAtCapacity` ([src/renderer/src/lib/account-live-sessions.ts](../../src/renderer/src/lib/account-live-sessions.ts)), which wraps the shared `usageHasBudgetHeadroom` ([src/shared/account-pool.ts](../../src/shared/account-pool.ts)) — the SAME capacity rule the spawn picker uses, so "waiting" can never disagree with which accounts the load balancer treats as full. Locked by [tests/unit/components/LiveSessionChip.test.tsx](../../tests/unit/components/LiveSessionChip.test.tsx) + the `isAccountAtCapacity` block in [tests/unit/lib/account-live-sessions.test.ts](../../tests/unit/lib/account-live-sessions.test.ts).
- **In-session surface (display-only):** the parked-session banner lives in [src/renderer/src/features/sessions/SessionPanel/SessionStatusBanners.tsx](../../src/renderer/src/features/sessions/SessionPanel/SessionStatusBanners.tsx) (gated on `session.status === 'waiting'`, no action button). The account-switch caption is [src/renderer/src/features/sessions/RateLimitRecoveryCaption.tsx](../../src/renderer/src/features/sessions/RateLimitRecoveryCaption.tsx) driven by `deriveRateLimitRecoveryCaption` in [src/renderer/src/features/sessions/recovery-captions.ts](../../src/renderer/src/features/sessions/recovery-captions.ts), which gates on `ACCOUNT_MOVE_RECOVERY_TRIGGERS` (read via its `isAccountMoveTrigger` helper) from [src/shared/rate-limit-recovery-triggers.ts](../../src/shared/rate-limit-recovery-triggers.ts) — that shared module is the source of truth for the trigger set, and `coalesce-system-rows.ts` only re-exports the caption helper. Fires only for the account-MOVE triggers `account-switch` / `lb-respawn` / `lb-rebalance`; mirrors the auth-refresh `RecoveryCaption`, mounted in [src/renderer/src/features/sessions/TurnGroup.tsx](../../src/renderer/src/features/sessions/TurnGroup.tsx). When ONE turn carries BOTH this switch caption AND the auth-refresh `RecoveryCaption`, the two render in chronological (`firstTimestamp`) order via `orderRecoveryCaptions` — the earlier event on top — not a fixed recovery-then-switch order (2026-07-23 fix: a 12:52 AM switch was drawing below a 1:58 AM refresh). Both are additive — the in-flight inline marker is unchanged. Locked by [tests/unit/features/sessions/session-status-banners-rate-limit.test.tsx](../../tests/unit/features/sessions/session-status-banners-rate-limit.test.tsx) + [tests/unit/features/sessions/rate-limit-recovery-caption.test.tsx](../../tests/unit/features/sessions/rate-limit-recovery-caption.test.tsx) + [tests/unit/features/sessions/TurnGroup-recovery-caption-order.test.tsx](../../tests/unit/features/sessions/TurnGroup-recovery-caption-order.test.tsx). Contract: [.claude/memory/contracts/account-capacity-silent-recovery-contract.md](../../.claude/memory/contracts/account-capacity-silent-recovery-contract.md) the-park-and-switch-have-a-visible-in-session-surface.
- **Capacity-wait fleet gate (`the-fleet-capacity-gate`):** the bounded-window sweep in [src/main/services/rate-limit-recovery/capacity-wait-visibility.ts](../../src/main/services/rate-limit-recovery/capacity-wait-visibility.ts) (`sweep` / `readFleetCapacity` / `maybeRaiseWave` / `nudgeOnce`) surfaces the ember `waiting` state + raises the coalesced *"Sessions waiting on account capacity"* inbox alert ONLY when the fleet is genuinely exhausted — it probes `fleetHasFreeCapacity` (the shared `anyEligibleAccountHasCapacity` = `pickBestAccount` on cached usage, in [src/main/services/rate-limit-recovery-service.ts](../../src/main/services/rate-limit-recovery-service.ts)) once per tick; while any account has room a past-window session stays silent + is nudged to re-route. A 10-min absolute backstop (`CAPACITY_WAIT_ABSOLUTE_SILENCE_MS`) still surfaces a wedged session (bounded silence) without the false alarm; fail-visible on a probe throw; kill switch `AMC_DISABLE_CAPACITY_FLEET_GATE=1`. Locked by [tests/unit/services/rate-limit-capacity-wait.test.ts](../../tests/unit/services/rate-limit-capacity-wait.test.ts) (the 5 the-fleet-capacity-gate cases). Contract: [.claude/memory/contracts/account-capacity-silent-recovery-contract.md](../../.claude/memory/contracts/account-capacity-silent-recovery-contract.md) the-fleet-capacity-gate.
- Invariants + safe-change rules: [.claude/memory/contracts/account-switch-contract.md](../../.claude/memory/contracts/account-switch-contract.md) (see the "Header surfacing" note).

## Related

Accounts themselves — adding one, signing in, and what happens when one hits its rate limit — are covered by the accounts documentation in this library.
