Skip to content

[Feature]: Account switch must not require restarting running sessions — restart is unusable when orchestrating dozens of concurrent Claude panes #34422

Open

Description

@JakeB-5

Problem or use case

I run multi-agent workflows in Orca: one coordinator plus dozens of Claude Code worker panes running in parallel, each in its own worktree, often for hours. I keep several Claude Max accounts. When the active account hits its 5-hour or weekly limit, I switch accounts in Orca.

Up to v1.4.224, switching accounts just worked: every running session kept going on the new account at its next request. Nothing restarted, and no conversation, in-flight turn or worker state was lost. It is the main reason I use Orca.

Since v1.4.225, with the per-account claude-profiles/<id>/home routing (still the case on v1.4.242, macOS 27.0.1), each claude process gets its CLAUDE_CONFIG_DIR when it starts. A running session can no longer move to another account. The only option left is the "When you switch accounts while Claude is running" setting (claudeAccountSwitchRunningSessions: Ask / Always restart / Never restart), and restarting does not work at this scale:

So the new model forces me to choose between a mass restart that loses work and a stalled run. If this is how it stays, I can no longer use Orca for this workflow.

Proposed solution

Bring back the pre-v1.4.225 behaviour as an opt-in setting, as proposed in #29999: a "shared login" mode where switching accounts updates the shared credential that running sessions read. Running Claude Code sessions then switch at their next request, with no restart.

Per-account profile isolation can stay the default for people who want sessions pinned to an account. People who orchestrate many long-running agents need running sessions to move without a restart.

Alternatives or additional context

Activity

  1. nachumi-a2zoperations commented on Nov 2, 2026

    @nachumi-a2zoperations

    We run the workflow described here (one coordinator, many long-lived worker panes, several subscription accounts) and have had restart-free moves working in a local build since 2026-10-29. Posting the design because it is small, keeps #26801's per-account folders intact, and we would like to contribute it.

    Why a running session cannot move today

    A Claude Code process reads its login once, from its own CLAUDE_CONFIG_DIR. After #26801 every managed account has its own folder, so the process is pinned to one account for life. Orca can only change the account by stopping the process and starting another one. That is what "Restart session" does, and it is what breaks the orchestration case: dozens of panes mid-turn, each with a conversation, background monitors, and a coordinator waiting on them.

    The idea: separate "which folder the process runs in" from "which account pays for the next request"

    Claude Code honours ANTHROPIC_BASE_URL. Orca already owns the launch environment. So Orca starts one loopback HTTP listener per execution host and gives each Claude session a slot URL:

    ANTHROPIC_BASE_URL=http://127.0.0.1:<port>/p/<slot>/
    

    The proxy forwards every request to https://api.anthropic.com unchanged (method, path, query, body, streamed response including SSE) except for one header: Authorization is replaced with Bearer <token> for the account currently assigned to that slot. The token is re-read from that account's credential store on every request, so the proxy never caches or refreshes a token itself.

                before                                        after
     ┌─────────────┐                              ┌─────────────┐  ANTHROPIC_BASE_URL
     │ claude (A)  │──Authorization: A──► api     │ claude (A)  │──────────────┐
     └─────────────┘                              └─────────────┘              ▼
       pinned to A's folder                         still in A's folder   ┌───────────────┐
       for the life of the process                  (transcript, /status) │ 127.0.0.1 proxy│──Bearer <slot→B>──► api
                                                                          │ slot 7 → B     │
                                                                          └───────────────┘
                                                                            ▲ the move: one map write
    

    A move is one in-memory write: slot 7 now maps to account B. The process keeps running. Its next request is billed to B. Nothing is restarted, no conversation is lost, no worker notices.

    What stays on the original account, on purpose

    Stays with the spawn account (folder A) Follows the slot (account B)
    transcript directory, claude --resume from a shell every API request, so usage and limits
    /status email, .claude.json the pane's account badge in Orca
    settings/MCP mirrors of that folder orca account list attribution

    We chose to accept this instead of relaunching under another folder, because that relaunch is exactly the restart everyone here is trying to avoid. The registry records both ids (accountId = spawn, assignedAccountId = billed) so every surface that reports "which account is this pane on" shows the billed one.

    How it plugs into what exists

    • Launch. launchEnv / prepareLaunchFor add the slot URL when the proxy is listening and the setting is on. A user-set ANTHROPIC_BASE_URL is never overridden (logged once). Off = today's behaviour exactly.
    • Registry. The pane registry gains assignedAccountId and proxySlot. Usage attribution, the auto-switch "running sessions" scan, and account list read the assigned id when it differs from the spawn id. Live statusline posts carry the pane key, so a moved pane's usage is billed to the right account and not dropped for a config-dir mismatch.
    • Mover. Where today's switch would decide "restart this pane", the policy first asks "does this pane have a slot?". If yes, it uses the proxy strategy: flip the slot, update the registry, return moved with the same pty id. No spawn, no hand-off note. Only a pane without a slot (started before the proxy, or with a user-set base URL) falls back to today's restart path. Mid-turn and background-work waits are skipped for a proxy move because there is no process to protect.
    • Resume. A later --resume of that session id, with no explicit account, launches on the remembered billed account.
    • Headless. The listener lives in the account services, so it runs on orca serve hosts too ([Feature] Switch running Claude sessions to the new account on a headless/remote host (account switch via RPC/CLI, usage-limit event) #31476). A move there is driven by the same rate-limit event or by the CLI.
    sequenceDiagram
      participant RL as RateLimitService
      participant M as mover policy
      participant Reg as pane registry
      participant Px as auth proxy (127.0.0.1)
      participant C as claude process (pid unchanged)
      RL->>M: account A at 90% weekly
      M->>Reg: panes on A with a slot?
      Reg-->>M: pane 42, slot 7
      M->>M: pick target B (most headroom, not pinned, cooldown ok)
      M->>Px: slot 7 → B
      M->>Reg: pane 42 assignedAccountId = B
      M-->>RL: moved (same pty), notice "A is near its usage limit. The session continues on B without a restart."
      C->>Px: next request, Authorization: A
      Px->>Px: replace with Bearer <B>
      Px-->>C: streamed response
    
    Loading

    Surface

    • Settings › Accounts › Claude: "Bill Claude through a local auth proxy" (next to the restart policy row). Off by default in the PR.
    • orca account auth-proxy --agent claude --on|--off; account list prints auth-proxy: on|off and, after a move, pane <ptyId>: account <id>; JSON carries authProxy and paneAssignments.
    • Desktop notice when the pty did not change: "{from} is near its usage limit. The session continues on {to} without a restart."

    Verified in use

    • Two sessions moved in both directions on a Mac desktop and on a headless serve host; the pid stayed, the response organisation and weekly fraction switched to the target on the next prompt; /status still showed the spawn email as described above.
    • An orchestration run with a coordinator and workers across three accounts over several days with no restart caused by account changes.
    • 19 test files / 165 tests on the proxy (header replacement, SSE pass-through, unknown slot, token re-read), registry, strategy, policy, router env, spawn auth, RPC, CLI, renderer scan.

    Limits we know

    • Windows, WSL and SSH execution hosts are guarded but not implemented: the listener is loopback per host, so a remote host needs its own listener on its loopback. Not in the first PR.
    • The split described in the table above (transcript folder vs billed account) is the product trade-off. If maintainers prefer, the badge could show both.

    We would open this as two PRs on main: (1) the proxy and slot registry, defaults off; (2) the mover's proxy strategy on top. Both small enough to read in one sitting. Does that shape work for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions