Repository navigation
[Bug]: Active Claude managed account is materialized into the user's default CLAUDE_CONFIG_DIR — sessions launched outside Orca bill the selected account #16016
Description
Operating system
Windows (11 Pro, 10.0.26200)
Orca version
v1.4.182
Details
Short summary:
On the host runtime, an active Claude managed account is materialized into the resolved default CLAUDE_CONFIG_DIR — the same directory the user's own Claude CLI uses outside Orca. Every Claude process resolving that directory then bills the selected account, including sessions Orca did not launch. The WSL runtime already avoids this by injecting a per-account CLAUDE_CONFIG_DIR instead.
What happens
syncForCurrentSelection writes the managed account's credential straight into the resolved runtime paths, then rewrites that directory's .claude.json identity field:
src/main/claude-accounts/runtime-auth-service.ts:422-423—const paths = this.pathResolver.getRuntimePaths()→this.writeRuntimeCredentials(credentialsJson)src/main/claude-accounts/runtime-auth-service.ts:437→writeRuntimeOauthAccount()(:1586-1601), which writesexisting.oauthAccountintogetRuntimePaths().configPath
The pre-swap state is snapshotted to claude-runtime-auth/system-default-auth.json and restored only on selection-change paths (:144, :249-253, :309-339, :429). I could not find any quit-time handler or startup reconciliation in the service, so if the app exits without a selection change, the foreign credential stays in the user's default directory.
The consequence is not Orca-scoped: the swap is a property of the directory, not of the panes Orca spawns. A claude session started from any terminal, a cron job, an editor extension, or another tool resolving the same directory bills the selected account for as long as the selection is active. In our case personal sessions billed a work account for hours; we found it through usage numbers, not through anything in the UI.
The WSL runtime already does the right thing
:619-624 returns { configDir: managedAuthPath, envPatch: { CLAUDE_CONFIG_DIR: wslLinuxAuthPath }, stripAuthEnv: true } — per-account isolation, nothing shared touched. The rationale is stated in-tree at :293:
"WSL managed accounts are isolated by their Linux
CLAUDE_CONFIG_DIR; materializing into Windows~/.claudewould mix two auth stores."
That reasoning applies verbatim to the host path. Host is the outlier, not the norm.
Reproduction (Windows, no CLAUDE_CONFIG_DIR override)
- Add two Claude managed accounts, A (personal) and B (work).
- Select B as the active account in Orca.
- Outside Orca, in a plain terminal, run
claudeand send any prompt. - The usage is billed to B.
%USERPROFILE%\.claude\.credentials.jsonholds B's credential and.claude.json'soauthAccountis B. - Kill Orca (Task Manager / crash) without clearing the selection. B's credential and identity remain in the default directory.
What I'd expect
- Never write managed credentials into a config dir the user also uses outside Orca. The active selection should resolve to the account's own
managedAuthPathand be injected per spawn — the mechanism at:619-624, applied to host. - Failing that: reconcile at startup and restore on quit, so a crash cannot leave a foreign credential behind.
Why this is not #6921 / #14254
#6921 (per-worktree binding) is explicitly additive — "Unassigned worktrees are unchanged". It adds an opt-in path that avoids materialization; it does not remove materialization for the global selection. Every user who does not bind every worktree keeps this behavior. Its implementation PR (#6963) was withdrawn by its author on 2026-08-21, so it is not a scheduled fix either. #14254 was my own feature request for Codex-parity per-pane selection; this is the defect underneath it, filed separately because it stands on its own and does not require that feature to land.
Precedent: the Codex equivalents of exactly this class are tracked as their own open issues — #8612 ("Orca silently redirects system Codex state away from ~/.codex") and #5370 ("Orca's private CODEX_HOME causes an auth-revocation war with the user's ~/.codex").
Note on scope: an earlier report of mine claimed the swap leaves oauthAccount stale. That was wrong — :437 does write it. The billing and crash-persistence behavior above is unaffected by that correction.
Open question: on entry, captureSystemDefaultSnapshotForManagedEntry (:1136-1159) preserves the prior snapshot when the runtime credential equals the managed one, which covers a crash-leftover of the same account. If Orca restarts with a different account selected, the leftover credential differs from the newly-managed one and takes the force: true branch — is the foreign credential then recorded as the system default? I have not reproduced this and may be misreading the flow.
Activity
fbaltor commentedon Sep 10, 2026
Corroborating the shared-runtime credential mechanism on NixOS/Linux x86_64, Orca 1.4.199, Claude Code 2.1.267, using a headless Orca server and a remote laptop client.
Our reproduction confirms an existing session's displayed account changes after switching the managed account. We have not verified cross-account billing or credential persistence after a crash, so this is narrower than the full reproduction in the issue body.
Steps and observed result
orca-ide account add --agent claude.claude. Run/status: it shows A. Keep this process open.claudesession:/statusshows B./statusagain. The same session ID now shows B, without restarting it or running/loginthere.Read-only
/procinspection confirmed both test Claude processes had the same home directory, withCLAUDE_CONFIG_DIRandCLAUDE_SECURESTORAGE_CONFIG_DIRunset. Neither process hadANTHROPIC_API_KEY,ANTHROPIC_AUTH_TOKEN, orCLAUDE_CODE_OAUTH_TOKENin its launch environment. No credential values are included here.Source confirmation in v1.4.199
runtime-paths.tsresolves the host runtime to the shared default Claude directory when no override is inherited.runtime-auth-preparation.tsreturns shared paths for the host branch, while the managed WSL branch supplies a per-account config directory.runtime-auth-sync.tswrites both runtime credentials and account metadata for the selected account.runtime-auth-service-deselect-restore.test.ts, beginning at line 180, explicitly asserts replacement of the shared credentials and metadata when selecting different accounts. We inspected this test; we did not execute it.The account-switching documentation describes existing Codex sessions retaining their original account and then presents Claude switching as identical. That led us to expect isolation, which this host implementation does not provide. At minimum, the documentation should distinguish the two behaviors; ideally, host launches should receive separate account-specific credential directories without rewriting the default login.
We support fixing the shared-directory behavior tracked here. The changed
/statusidentity is evidence of shared account state, not proof of which cached token a subsequent inference request uses or which subscription it charges.johnmarktaylor91 commentedon Sep 14, 2026
Additional evidence from a Linux server-mode install (Orca 1.4.201, Claude Code 2.1.270).
I quarantined
~/.claude/.credentials.jsonthree times in one evening and it came back each time, byte-identical (same SHA-256) to the token of the active managed Claude account. A 2-second poller caught the third recreation at 22:41:40Z: noclaudeprocess had been started in the preceding minute; the only new process was Orca's own Codex app-server spawn one second earlier, so the write comes from the Orca main process itself, not from a launched CLI.Consequence on a shared host: any plain
claudeinvocation that reaches the default config directory silently bills the managed account. I now route typedclaudethrough a wrapper that requiresCLAUDE_CONFIG_DIR, but a way to disable the materialization (or scope it to Orca-launched processes only) would remove the hazard at the source.Justin3546 commentedon Sep 20, 2026
Confirming on macOS host runtime, v1.4.206 (Darwin 27.0.0). Same root cause, with one outcome that is worse than the Windows report and one gap in the restore path.
Setup that makes it sharp
Several sibling Claude config dirs, each holding a different account, selected per-process with
CLAUDE_CONFIG_DIR:So
~/.claudeis not "the default directory", it is a specific account. Both use the same email and differ only by organization, which is also why #21182 bites here: nothing in the UI distinguished them.What happened
Added both as managed accounts. Within the same minute,
~/.claude/.claude.jsonwas rewritten with the active managed account'soauthAccountidentity. More importantly, the displaced account was left fully signed out, not merely mis-billed:The Windows report describes foreign credentials billing the wrong account. On macOS the original credential is moved, so the directory is left with no usable login at all. Recovery was a manual
claude auth login; nothing in Orca offered to put it back.The snapshot is captured but not restored on account removal
claude-runtime-auth/system-default-auth.jsonwas written at the moment of the swap, containingcredentialsJson,configOauthAccount,keychainCredentialsJson,scopedKeychainCredentialsJson,legacyKeychainCredentialsJsonandcapturedAt. Capture works.Removing all managed Claude accounts did not restore it. Afterwards the account list is empty,
claude-accounts/is empty, theOrca Claude Code Managed Credentialskeychain item is gone, and the displaced directory was still signed out until I logged in by hand. The snapshot file remains on disk, unrestored.So the restore gap is wider than "app quits without a selection change". Removing the managed accounts is also a path that leaves the resolved default clobbered.
The Codex path in the same build does the right thing
Managed Codex accounts never touched the real
~/.codexor~/.codex-firm; both kept their originalaccount_id. That is the same isolation this issue notes WSL already does for Claude viaenvPatch: { CLAUDE_CONFIG_DIR: ... }. Host Claude looks like the only one of the three without an isolated home.Suggested fixes, in preference order:
CLAUDE_CONFIG_DIR, as WSL Claude and host Codex already do. Never write into the resolved default dir.OrcaWin commentedon Oct 11, 2026
Thanks for the careful analysis. This is fixed on main by #26801: managed Claude accounts now live in per-account folders that Orca's launches point to, so the default CLAUDE_CONFIG_DIR is no longer rewritten.