---
title: Switch active account
---
# Switch active account

## What it is

There is **no traditional "switch account" button in Omniscio** — and you almost never need to switch manually. When you have more than one Claude account configured, Omniscio's **account pool** picks an account for each new session at spawn time. The session header shows a small indicator with the active account's email and a colored capacity dot, so you can always see who is powering the running session, but there is no per-session account dropdown to change mid-conversation.

> **Read this first — which mode you are in changes what "active account" means.** **Load
> balancing** (`distributeSessionsAcrossAccounts`) 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), so the pin-first behaviour this page's steps describe IS the default.
> When you turn load balancing **ON**, it deliberately **spreads new sessions across your
> accounts instead of preferring the active one** — "Activate" then does **not** pin every
> spawn; it sets the display default and moves your existing sessions, and new spawns are
> still spread. Both modes are covered below, and the mechanics live in
> [distribute-sessions-across-accounts.md](distribute-sessions-across-accounts.md).

With load balancing **off**, the active account (the one you've "Activated" or that Omniscio defaulted to) acts as a soft preference — the pool uses it first if it has capacity, then transparently falls through to other accounts if it doesn't, scoring the rest by remaining 5-hour and 7-day capacity.

This is intentional. Mid-turn switching would invalidate the CLI's auth context, and the pool handles 95% of the "I'm running low" cases without the user having to think — by spreading across accounts under load balancing, or, with it off, by walking the tier list (pinned → primary capacity → extra credits → API key). The two places "switching" actually happens in the UI are: (1) clicking **Activate** next to an account row in **Settings → Accounts**, which sets the preferred-account flag; and (2) the silent automatic switch the pool does at the next spawn — covered in [account-pool.md](account-pool.md).

## Where to find it

**Settings → Accounts** — each account row carries an **Activate** link. The session header shows which account is powering a running session.

## How it behaves

### How to use it

1. **Default behavior — do nothing.** When you start a new session the pool picks for you, and the session header shows that account's email.
   - **Load balancing ON (the default):** the picker (`pickViaLoadBalancer`) deliberately **ignores the pinned account** and spreads the session onto whichever account is least loaded, scoring by `max(5h,7d)` plus live-session and in-flight penalties minus a soon-to-reset bias.
   - **Load balancing OFF:** the pool reads cached usage data, scores each login account by `max(5h_utilization, 7d_utilization)`, and uses the lowest-utilization one — but keeps using your active (preferred) account first while it still has capacity.

2. **Pin a preferred account.** Open **Settings → Accounts**. Each account row has an **Activate** link unless it's already the active one (green dot, `bg-accent/10` highlight). Click **Activate** to pin it. There's no separate "Pin" toggle — **Activate** is how you pin. What pinning actually buys you depends on the mode:
   - **Load balancing ON (the default):** Activate **does not pin future spawns**. It moves your EXISTING sessions (that is treated as deliberate user intent) and becomes the display default, but new sessions keep being spread. To get "everything on one account" back, turn load balancing off in **Settings → Accounts**.
   - **Load balancing OFF:** the pool prefers this account on every spawn, falling through only when it hits its caps.

3. **Read the session header indicator.** The toolbar shows a small `AccountIndicator` (CircleUser icon plus a percent capacity dot). Click it to see the active account's email, plan tier, and 5-hour / 7-day usage bars; the popover also lists every other account so you can see at a glance who else is in the pool. **When the active account changes** — whether you clicked Activate yourself or the silent rate-limit auto-switch picked a different one — the pill plays a brief 700 ms left-to-right shimmer flash so you notice the swap without it feeling intrusive. The same flash plays on the mobile chip in the tab bar. The animation is suppressed under `prefers-reduced-motion`.

4. **What happens mid-turn.** Once a session has spawned, Omniscio does **not** swap the account out from under it for the rest of that turn — the spawned CLI process holds the active account's credentials in env vars and runs to completion. The pool re-evaluates only at the next spawn (a brand-new session, or a **Continue** after rate-limit recovery). A rate-limited session that recovers can transparently resume on a different account; the system message reads "resuming on current account" or "switching to <email>" depending on which path the recovery service took (see [session-stuck-in-needs-you.md](session-stuck-in-needs-you.md) "Rate Limited" case).

5. **Force a specific account for one session (advanced).** Turn **load balancing off** first — with it on, the picker ignores the pin and the trick below does nothing. Then: pin that account via **Activate** before clicking **New Session**, let the spawn happen, and re-pin your usual account afterwards. There is no "lock this session to account X" affordance — `account_id` is recorded on the session row at spawn but is overwritten by the pool's choice on every restart, so it isn't a hard binding.

6. **Auto-switch on rate limit (related setting).** **Settings → Accounts** also has an **Auto-Switch Account on Rate Limit** toggle (visible only when you have 2+ accounts; default on). **On a default install this toggle is inert** — while load balancing is on, `onSessionRateLimited` hands off to the LB-aware path before the global auto-switch is ever reached, so the automated whole-account switch is suppressed (the two would otherwise fight). What actually happens at a cap is the LB per-session recovery: only the capped session moves, onto an account that excludes the one that just capped, and your active account is left alone.
   - **With load balancing OFF**, the toggle behaves as written: when a session hits a 5-hour cap, the recovery service silently switches your whole active account to another with capacity and continues; toggling it off makes the session sit idle until the timer resets.
   - The **manual** Activate switch is unaffected in either mode.

7. **Auto-switch on login expiry (2026-07-03).** Rate limits aren't the only thing that moves a session to another account — a **login expiring** does too. If a session's Claude login goes stale and its silent auto-retries can't refresh it, Omniscio now hands the session to another account whose login is healthy and keeps it running, instead of dead-ending on **"Please re-authenticate."** It happens silently; the expired account keeps a **"sign in again"** badge in **Settings → Accounts** so you can fix it whenever. You only see the re-authenticate prompt when there's genuinely nothing to switch to — a single account, or every login expired. (Unlike rate-limit auto-switch, this isn't tied to the "Auto-Switch on Rate Limit" toggle — a dead login has no "wait for reset" alternative, so switching is always the right move when a healthy account exists.)

### How it works

The pool is the pure function `pickBestAccount()` in [account-pool.ts](../../src/shared/account-pool.ts). The process manager wires the active account into the call as the `pinnedAccountId` option — the function name is "pinned" but the value comes from `authService.getActiveAccountId()`, which is what **Activate** sets. Tier order: pinned account if it has any capacity (primary OR extra credits) → login accounts with primary capacity sorted by `max(5h, 7d)` ascending (freshest first) → login accounts relying on extra-usage credits sorted by remaining headroom descending → API key accounts. The `allowApiKeySessionSpawn` gate is enforced one step upstream — `pickActiveAccount()` in [process-manager.ts](../../src/main/process/process-manager.ts) calls `filterAccountsForSpawn()` from [api-key-guard.ts](../../src/main/process/api-key-guard.ts) FIRST to drop api-key accounts when the setting is off, so the pool's api-key tier never sees them. If every tier is empty, the pool returns `null` and the rate-limit recovery service fires the all-exhausted banner. The `pickActiveAccount()` wrapper reads the cached usage snapshot, calls the pure function synchronously, and kicks off a background usage refresh so the next pick sees fresh numbers.

The renderer's "Activate" link calls `useAccountStore.switchAccount(id)`, which invokes `IPC.ACCOUNT_SWITCH`; the handler in [claude-provider.ts](../../src/main/ipc/account/claude-provider.ts) calls `authService.switchAccount(parsed.id)` (which writes the new `activeAccountId` to `config.json`), validates the token via `ensureTokenValid()` for login accounts (so a stale refresh token surfaces immediately rather than at next spawn), kicks off `rateLimitRecoveryService.onAccountSwitched()` to auto-restart any rate-limited sessions on the new account, and notifies `aiSuggestionService.onActiveAccountChanged()` to invalidate the AI client. The renderer-side `switchAccount` is a **narrow within-user refresh** — it refetches the account list, usage rollup, and rate limits, and that's it. It does NOT reset projects, dividers, sessions, drafts (text/images/chips), channels, recipes, automations, git, file-explorer, or any other store, because none of those are account-scoped — they belong to the user, not the credential. (Wiping them caused two bugs in 2026-05: a placeholder/skeleton flash because the empty store lists hit `isLoading: true` rendering branches, and pasted images + chips disappearing because the module-level draft Maps were cleared. See `.claude/memory/postmortems/account-switch-no-refresh-postmortem.md`.) The full cascade only runs on `removeAccount()` and only when the removed account was active — and even then it's trimmed to channels (gmail/sms/channels), recipes, and automations, the three families whose state can plausibly reference the removed credential. The session header indicator is [AccountIndicator.tsx](../../src/renderer/src/components/ui/AccountIndicator.tsx); the row inside it is `LoginAccountRow.tsx` / `ApiKeyAccountRow.tsx` under [src/renderer/src/components/ui/account/](../../src/renderer/src/components/ui/account/). Mid-turn account staleness is caught by a load-bearing invariant in `writeToStdin()` — every reuse of a persistent CLI process checks that `session.spawnAccountId === authService.getActiveAccountId()` and force-kills the child for a fresh spawn if they differ (see [account-management.md](../../.claude/memory/account-management.md) "Persistent Process Reuse & Stale-Account Invariant").

**Login-expiry failover** lives on a different track than rate-limit recovery. Rate limits go through `tryAutoSwitch`; a login that keeps 401ing goes through the silent auth-retry state machine ([auth-error-handler.ts](../../src/main/process/auth-error-handler.ts)). Historically that machine only ever retried the SAME account and then escalated to the "re-authenticate" prompt. It now routes the per-credential give-up point through the pure `planAuthRetryDisposition` ([auth-failover.ts](../../src/main/process/auth-failover.ts)): if a healthy alternative login exists (its `auth` breaker is closed), it force-pins that account for the next spawn and re-runs the last turn; only when no healthy login remains does it escalate to re-auth. The failing account's breaker stays open (the "sign in again" badge), the retry episode is preserved so a second account also failing falls to the existing outage backoff (no loop), and single-account behavior is unchanged. Full invariants: [`an-expired-login-fails-over-before-it-escalates`](../../.claude/memory/contracts/account-switch-invariants-contract.md).

## Related

- [account-pool.md](account-pool.md) — the authoritative explanation of the tier-list and how the pool actually chooses
- [add-a-claude-account.md](add-a-claude-account.md) — adding the second (or third, or fourth) account that makes switching meaningful
- [remove-a-claude-account.md](remove-a-claude-account.md) — taking an account out, including what happens to its in-flight sessions
- [session-stuck-in-needs-you.md](session-stuck-in-needs-you.md) — the "Rate Limited" case where a silent cross-account resume kicks in
- [usage-forecast.md](usage-forecast.md) — the inline projection that tells you when the active account will run out, so you know whether to pin a different one
