---
title: Session stuck in "needs you"
---

# Session stuck in "needs you"

## What it is

"Needs you" (amber pulsing dot, label `Needs You`) is not a stuck state — it means the session has paused itself on purpose and is waiting for a decision only you can make. The agent will not proceed until you resolve whatever it flagged. The specific reason is shown as a sub-label on the session dot (e.g. "Question", "Permission", "Plan approval", "Auth Error", "Stopped") and each one has a different fix. **"Rate Limited" is not one of these any more** — since 2026-07-20 it is its own `waiting` status (item 4 below), not a "Needs You" sub-label.

## Where to find it

You meet this in the session list rather than a screen of its own: a session that needs you shows an amber row with a sub-label beside its status dot — blue for a question, violet for a plan review, cyan for a permission prompt. Open the session to act, because the chat body says what it is waiting on and the answer is usually a button or the composer.

## How it behaves

### How to use it

Open the session. The body of the chat tells you exactly what it's waiting on. Match what you see to one of these causes:

**1. Question widget is open (blue dot, label "Question")**

- What you see: The agent's last message actually asks you something — usually a choice card (an `AskUserQuestion` / question-widget with options) or a message ending in a question mark. (Since 2026-06-28 the blue "Question" dot appears ONLY when the FINAL message asks something: a turn that asked mid-way but then wrapped up without a question mark shows plain amber "Needs You" instead — see `waiting-detector-contract.md` `a-final-message-without-a-question-is-not-asking`.)
- What to do: Click an option (or press the number key). If none fit, type a free-text reply in the composer and hit Send. Either action submits the answer and the session flips back to "Running".

**2. Plan awaiting approval (violet dot, label "Plan Review")**

- What you see: The agent ran `ExitPlanMode` and posted a proposed plan; it will not execute until you say yes. A banner appears above the composer with two buttons: **Approve plan** and **Request changes**.
- What to do: Read the plan, then click **Approve plan** — it sends the canonical approval ("Approved. Proceed with the plan.", the same text Omniscio's auto-approve setting sends) and the agent starts executing. To push back, click **Request changes** (it just puts your cursor in the message box — describe the changes in your own words) or type any reply directly. The next message clears the state either way.

**3. Tool permission prompt (cyan dot, label "Permission")**

- What you see: A permission prompt inline in the chat — the agent wants to modify a config file or run a tool that needs sign-off. The card names the requesting tool in a small "Tool:" chip (e.g. `Edit`, `Bash`) above the file path, so you can judge the ask before deciding.
- What to do: Click Approve or Deny on the prompt. Approving lets the tool run; denying sends the refusal back so the agent can try a different approach.

**4. Rate-limited (orange dot, label "Rate Limited") — now its OWN `waiting` status, no longer a "Needs You" sub-state (2026-07-20)**

> **What changed:** a rate-limited session no longer sits in the amber `needs_you` family at all. It moves to the dedicated **`waiting`** status — same familiar ORANGE dot and "Rate Limited" label, its own sidebar count — and is structurally invisible to every attention surface (inbox, amber badge, chime). Silent account-switching stays invisible for up to ~2 minutes; past that the session flips to Waiting and writes a transcript line — "Waiting for account capacity — resumes automatically…" — so a long weekly-cap wait can never masquerade as a working "streaming" session again (the 2026-07-20 storm). One coalesced inbox alert per storm wave replaces per-session noise. Crash-restart also parks straight into Waiting instead of burning a resume turn on a capped account. Kill switch: `AMC_DISABLE_CAPACITY_WAIT_STATE=1`.

- What you see: A banner saying usage limit reached. The session stopped mid-turn because your plan quota was hit. The usage bar on the session panel shows red at 100%+; hovering it shows the **absolute** reset time ("Thursday 5:00 PM") not a countdown.
- What to do: If you have other accounts with capacity, you normally **won't see this dot at all** — the session moves to a free account and keeps running silently, zero action from you. The orange **Rate Limited** dot now appears **only when no account has capacity left**: Omniscio then sets a timer, auto-resumes when a window opens, and shows an amber **"All accounts are at their usage limit"** banner at the top of the sidebar — click its **View Accounts** button to add capacity. Because it recovers on its own, an auto-recovering rate limit **no longer shows up in the inbox, rings a chime, bumps the Needs-You count, or pulls your window** — it stays quietly reachable in the sidebar's live list with its **Rate Limited** dot while Omniscio keeps retrying, so that amber banner is the one signal for the whole batch instead of a pile of rows that look like emergencies. (A session that genuinely _gives up_ after exhausting recovery now collects in the sidebar's **Interrupted** section as **Recovery Failed** — as of 2026-08-21 a give-up no longer nags from the inbox; it waits there for when you're ready.) You can also press Continue manually once any limit clears.
- This also covers a session that couldn't **start (or restart)** because every account was momentarily out of capacity — rate-limited or its circuit-breaker tripped. It parks here and auto-resumes when one frees up, instead of the old, misleading "credentials could not be decrypted — sign in again" message (that was the wrong fix for a rate limit). See [spawn-credentials-routing-contract.md](/.claude/memory/contracts/spawn-credentials-routing-contract.md).

**5. Auth error (orange dot, label "Auth Error")**

- What you see: Credentials are genuinely missing or couldn't be decrypted — e.g. no Claude account is signed in, or a stored token failed to decrypt. This is now reserved for **real** credential failures: a session that simply couldn't find a free account because everything was rate-limited shows **"Rate Limited"** (above), not this.
- What to do: Click **Continue** on the session — Omniscio will refresh the token and retry. If that keeps failing, open Settings → Accounts and re-sign in to Claude. **Revoked logins are flagged in Settings → Accounts** with a **"Log In"** button (even before their token visibly expires), so you can see exactly which accounts to fix. If EVERY login is revoked, the session lands in a durable "re-authenticate" state and names the dead accounts in the chat.
- **Hardware-swap / keyring-reset case:** a CPU or motherboard change resets Windows' credential store (DPAPI), so Omniscio can no longer decrypt accounts that were signed in before the swap. When Omniscio picks such an account, it now sidelines it instead of re-picking it and thrashing the fleet, and fires the **"Login Expired — sign in again"** notification once for that specific account so you know which login to fix — capacity is never lost silently. Re-signing in clears it immediately (no app restart needed) and resumes work. The same swap can also reset the system clock; Omniscio's reset timers and load-balancing are now clock-jump-safe, so a corrupted clock can't make a rate-limited session wait forever or spin restarting.

**6. API error (red dot, label "API Error")**

- What you see: An upstream error from Anthropic (network hiccup, 5xx, unexpected response).
- What to do: Click Continue to retry. If it repeats, check your internet, then send any message to force a fresh turn.
- **Context limit hit (long sessions / Kimi & other large-context models):** if the message reads _"This conversation got too long and hit the context-window limit,"_ the conversation has outgrown the model's hard token window — **retrying won't help.** Start a **fresh session** to keep going (or switch to a model with a larger context window). Before this fix such a session went silently to "Needs You" with no message; it now surfaces this clear error. See [context-limit-400-surfacing-contract.md](/.claude/memory/contracts/context-limit-400-surfacing-contract.md).

**7. You stopped it (red dot, label "Stopped")**

- What you see: You (or a keystroke) hit Escape / Stop mid-turn. It shows a **red** dot (the same red as an error) so a stopped session stands out and gets counted in the sidebar's red number — but it isn't a failure; the agent just paused where you interrupted it. (This dot was pink before 2026-07-20; it's red now.)
- What to do: Send any message to resume. The agent picks up from where it was interrupted.

**8. Recovery failed (red dot, label "Recovery failed") — the session gave up recovering (now in the Interrupted section as of 2026-08-21, NOT Needs You)**

- What you see: The session crashed or lost contact and Omniscio's auto-recovery **retried and gave up** (it retries several times, across your accounts, first). It shows a **red** "failed" dot — a genuine failure, not a normal question. **As of 2026-08-21 a give-up did not deliver a final message, so it collects quietly in the sidebar's Interrupted section — NOT Needs You, and it no longer chimes.** (This reverses the 2026-08-14 rule that surfaced it in Needs You: Needs You is now only for sessions that delivered a real message and need your response; every failure/give-up goes to Interrupted, where it's still fully visible and one-click retriable.)
- What to do: Find it in the **Interrupted** section, open it, and send any message to resume — that resets the give-up and relaunches from where it left off — or archive it if you're done. It won't auto-retry again on its own.

**9. Routine update (amber dot, label "Routine update") — normally invisible, and NOT a stuck state**

- What you see: a finished session that is nowhere in your inbox, and — if you open it — a muted grey strip pinned above the conversation: **"Resting — nothing needed you this round, so it is not in your inbox."** Hovering it explains that the turn's reply was parked as routine, that the whole reply is right there in the conversation, and that the session returns to your inbox the moment it takes another turn. (The sidebar dot may also read "Routine update" briefly on a client that has not refreshed yet.) The turn deliberately stays out of your inbox, the sidebar's Needs-You list, the badge and the chime instead of asking for you.
  - Two things park a turn this way: the agent tagged its own reply as a routine update, or it answered Omniscio's "are you really still waiting?" check with a one-line card you have cleared. Either way the session's status still reads "needs you" while every surface ignores it — which is exactly why the strip is there, since without it the session is a dead end.
  - A **silenced** session shows no strip. It is kept off the inbox for its own reason (silent recipe sessions are hidden from every attention surface in every status), so the strip's promise would not be true of it.
- What to do: nothing. Open the session whenever you like — the reply is right there, and **Everything it does** shows the tagged turn in the chat view. Want it in your inbox after all? Send it any message: the park lifts the instant the session takes another turn, and there is deliberately no timer on it. Turn the behaviour off in **Settings → Session → "Hide routine updates from the inbox"** to have every finished turn reach your inbox as it did before. A turn that asks you something is never quieted, an untagged turn is unaffected, and a routine turn is refused outright when the session was already holding something you had not seen — so this can never hide an earlier reply from you.

If the dot is amber with no sub-label, the session is in the generic `needs_you` state — open it and scroll to the last agent message; whatever it's asking is near the bottom.

## For agents

### How it works

Every session has a `pendingAction` field (type [`PendingAction`](/src/shared/types.ts)) alongside its `status`. The renderer looks up `pendingAction` in the `PENDING_ACTION_DISPLAY` map in [/src/renderer/src/lib/status-display.ts](/src/renderer/src/lib/status-display.ts) (re-exported by `lib/utils.ts`) to pick the colored dot, label, and tooltip. A pending action is not automatically a `needs_you`: **"Question", "Permission" and "Plan approval" are the sub-states of the one `needs_you` status**, while **"Rate Limited" is its own `waiting` status** (`waiting` + `pendingAction: 'rate_limited'`, see item 4 above) whose display style comes from that same map. The main-process [/src/main/process/process-manager.ts](/src/main/process/process-manager.ts) sets these when parsing NDJSON output from the Claude CLI (tool calls set `question` / `plan_approval` / `permission_request`; `user_stopped` is set when you interrupt). The rate-limit path is owned by [/src/main/services/rate-limit-recovery-service.ts](/src/main/services/rate-limit-recovery-service.ts), which clears the field on auto-resume. It also keeps a `needs_you` + `rate_limited` session OFF every user-attention surface — the inbox, the Needs-You badge/count, the completion chime + OS notification + window auto-focus, the attention toasts, and auto-switch-to-inbox — through the shared `isAutoRecoveringRateLimit` rule ([/src/shared/session-attention.ts](/src/shared/session-attention.ts)), since the recovery machinery resolves it without you; the session stays reachable in the sidebar's live list, and its recovery tracking is rehydrated on app restart so it never strands invisibly. A genuine give-up transitions to the still-visible `recovery_failed`. See [needs-you-visibility-contract.md](/.claude/memory/contracts/needs-you-visibility-contract.md) I12 and [account-capacity-silent-recovery-contract.md](/.claude/memory/contracts/account-capacity-silent-recovery-contract.md). **A genuine user gate is never swallowed by this hiding.** A session the agent posted a real question / plan-approval / permission request on (`needs_you` + `question`/`plan_approval`/`permission_request`) is blocked on YOU, not on capacity — so the capacity-wait sweep and the `updateSessionStatus` writer both refuse to demote it to `waiting` (only a `rate_limited` park converts), and any gate buried by this before the guard existed is restored to the inbox on the next app restart. Without this a finished gate could be flipped to the silent `waiting` state and vanish from the inbox (the 2026-07-21 incident). See [account-capacity-silent-recovery-contract.md](/.claude/memory/contracts/account-capacity-silent-recovery-contract.md) a-genuine-user-facing-gate-is-never-demoted (kill switch `AMC_DISABLE_GATE_PARK_GUARD=1`). The **same quieting now covers a session Omniscio paused across an app restart** (`needs_you` + `suspended`, set by the shutdown disposition so a mid-work session survives the restart): while auto-resume is on, the sibling `isAutoRecoveringSuspended` rule keeps it off every attention surface — inbox, badge/count, chime, OS notification, window focus, plugin badges — and the suspended-resume pass relaunches it on next launch, so restarting Omniscio no longer flashes a pile of paused sessions into your inbox. The key difference from a rate limit (which is _unconditionally_ hidden): this hide is **gated on your auto-resume setting**. With **auto-resume off** (Settings → the "bring sessions back when Omniscio restarts" switch, or the restart toast's Stop) nothing relaunches the session, so it stays **visible** in the inbox waiting for you — the anti-stranding safety net; a resume that then fails lands in the still-visible `error` / `recovery_failed`. See [needs-you-visibility-contract.md](/.claude/memory/contracts/needs-you-visibility-contract.md) I13. The hide now spans the **entire resume**, not just the paused state before it: a relaunched session's `--resume` can emit several empty "reloading" turns before real work streams (measured: 4 in 40 ms), and each was mis-read as "finished — needs you" and flashed into the inbox for a few seconds — dozens at once during a post-restart burst, the "rows popping in and out rapidly" report. Omniscio now treats the whole resume as one **episode**: the session stays hidden — and for Claude simply stays `running` at the source, so there's no status flip, DB write, or re-render churn behind it — until it produces genuine work, gives up, or a 10-minute safety timer fires; the hide is engine-agnostic (a non-Claude engine's genuine resume error surfaces immediately instead). So a restart no longer makes resuming sessions pop in and out. See [needs-you-visibility-contract.md](/.claude/memory/contracts/needs-you-visibility-contract.md) I14 (kill switch `AMC_DISABLE_RESUME_EPISODE=1`). When a spawn finds NO usable account, the empty-credentials guard ([/src/main/process/spawn-cluster-manager.ts](/src/main/process/spawn-cluster-manager.ts) → `onSpawnEmptyCredentials`) classifies _why_ and routes accordingly — pool momentarily exhausted ⇒ park + auto-resume (`rate_limited`), every login dead-token ⇒ durable `recovery_failed`, genuinely no credentials ⇒ `auth_error` — instead of always blaming undecryptable credentials. A **transient network outage is NOT a dead token**: when a token refresh fails because the network is unreachable (not because the credential was rejected), the account stays healthy, so an outage that hits every login no longer routes to the all-dead `recovery_failed` re-auth prompt — the spawn surfaces a transient "Network unavailable while refreshing token — please check your connection" message and recovers on its own when the network returns. Genuine revocations (refresh rejected with `invalid_grant`/401) still route to `recovery_failed`. See [auth-login-contract.md](/.claude/memory/contracts/auth-login-contract.md) `refresh-expired-tokens-automatically`. The [/src/renderer/src/components/ui/QuestionWidget.tsx](/src/renderer/src/components/ui/QuestionWidget.tsx) submits answers back through the standard send pipeline, which clears `pendingAction` as the next turn begins. The newest sub-state, `needs_you` + `overseer_status_update`, is the mirror image of the capacity hides above: the SESSION itself asked to be quiet, by ending its reply with the routine-update tag, and the shared `isOverseerStatusUpdateParked` rule then keeps it off the inbox, the sidebar's Needs-You list, the badge and the chime — all of which read that one predicate — with the dock-badge SQL and the chime re-arm mirrored in step. Unlike every other "something else owns this" hide in that file it carries **no timer**, and that is deliberate: the premise cannot expire, because it is the author's own statement about its own reply, and it is released the instant the session takes another turn. What keeps it safe instead is a **floor** at the disposition gate — the park is refused whenever the session was already waiting on you for something this feature did not itself park, so a routine turn can never bury an earlier reply you have not seen. The opposite tag, `[[OMNISCIO_ROUTE_TO_USER]]`, is the promote half of the same judgment: it beats the routine tag, exempts the turn from the quiet holds, and stamps `routedToUser` so the reply shows in "Just us" even on a turn you never opened. See [overseer-invariants-o72-o74-contract.md](/.claude/memory/contracts/overseer-invariants-o72-o74-contract.md).

## Related

- [account-pool.md](account-pool.md) — multi-account rotation and the exhausted-alert banner for rate-limit cases
- [snooze-a-session.md](snooze-a-session.md)
- [set-up-sms-integration.md](set-up-sms-integration.md)
