Repository navigation
[Bug]: Background /usage PTY spawns full Claude sessions, auto-accepts trust, and can execute tools/subagents #13086
Description
Operating system
macOS
Orca version
Reproduced on v1.4.174 and v1.4.176 (latest stable at the time).
Claude Code: 2.1.224.
Details
Short summary
Orca's background Claude usage/rate-limit machinery starts a real interactive claude PTY without explicit user initiation. The PTY inherits the user's full Claude configuration, hooks, plugins, MCP servers, and authentication. Orca then sends /usage, automatically accepts trust prompts, and repeatedly presses Enter without verifying that Claude is actually at a safe command-palette state.
On my machine this created 82 Claude session UUIDs/artifacts within one 30-minute window. At least one earlier hidden probe escaped the intended local /usage flow and performed real model/tool activity (Read + Agent), including launching a Sonnet subagent. This means an informational background usage probe can consume Claude quota and potentially execute tools or mutate files through user-installed hooks/plugins.
This appears more severe than #12181: that report covers background refresh creating ~/.claude; this report confirms real interactive sessions and model/tool execution.
What happened
Orca's source explicitly starts a full interactive Claude process:
claude-pty.tsdescribes an interactive/usagefallback- prompt detection is intentionally skipped in favor of a fixed 2-second delay
pty.spawn()launchesclaudewith no arguments inrate-limit-pty-cwd- the PTY presses Enter every 800 ms
- it sends
/usage, starts the Enter loop, and automatically answers trust prompts withy
The resulting Claude session hooks contained transcript paths such as:
export CODEX_COMPANION_SESSION_ID='700f543a-8bc8-42f7-8ca7-085bd20def2d'
export CODEX_COMPANION_TRANSCRIPT_PATH='$HOME/.claude/projects/-Users-user-Library-Application-Support-orca-rate-limit-pty-cwd/700f543a-8bc8-42f7-8ca7-085bd20def2d.jsonl'In the 30 minutes ending at 04:02:32 local time, I counted 82 distinct session IDs whose transcript path resolved to Orca's synthetic working directory:
$HOME/Library/Application Support/orca/rate-limit-pty-cwd
The final burst created new session IDs approximately every 5–7 seconds:
04:01:03 86238cb1-b103-4774-8962-f2a35ad41ed5
04:01:10 ff86644c-9b09-4c62-9e1d-9e8992577594
04:01:16 dc6e0330-f2fd-4927-919e-cbce0b8d2d8c
04:01:21 0d135a56-3fc7-4038-b4d5-825ce965b417
04:01:27 0b695541-446e-40fa-919d-66b2195e6d80
04:01:32 692dbd50-2a68-447b-bbd5-b59b8712c7fa
04:01:37 82c0f436-d7fd-42eb-a718-206ab56765dc
04:01:43 bdbbb404-2d9b-4a3a-b44f-d7f11aa7ed63
Because a single PTY repeatedly presses Enter, the count of Claude session UUIDs is not necessarily identical to the count of OS processes. However, I also captured a real live Claude process and its ancestry:
Orca main
-> Orca daemon-entry.js
-> orca-tcc-login
-> login zsh
-> claude --dangerously-skip-permissions --verbose
-> configured MCP/plugin child processes
Concrete PIDs from the capture:
6542 Orca
6917 Orca daemon-entry.js
40547 orca-tcc-login
40579 login zsh
41427 claude --dangerously-skip-permissions --verbose
Immediately before that PTY appeared, daemon.log recorded:
{"ts":"2026-08-07T20:00:29.456Z","event":"client-hello-accepted","clientId":"resolver-health-check"}
{"ts":"2026-08-07T20:00:29.475Z","event":"macos-tcc-pty-spawn","strategy":"wrapped"}
{"ts":"2026-08-07T20:00:29.476Z","pid":40547,"event":"session-created","sessionId":"folder:<redacted>@@d64caabf"}
{"ts":"2026-08-07T20:00:57.468Z","event":"session-exited","sessionId":"folder:<redacted>@@d64caabf","code":0}The Claude session created at the same time still used Orca's hidden rate-limit-pty-cwd, not the visible project directory.
Confirmed model/tool activity from an earlier hidden probe
A separate hidden session on v1.4.174 had this Claude session-stat entry:
"9cd4d201-42b8-422e-aee1-1822b1351b9d": {
"tool_counts": {
"Read": 1,
"Agent": 1
},
"last_tool": "Agent",
"total_calls": 2,
"started_at": 1786124400,
"updated_at": 1786124450
}Its transcript/project namespace was also Orca's hidden cwd:
$HOME/.claude/projects/-Users-user-Library-Application-Support-orca-rate-limit-pty-cwd/
The Agent tool created a real Sonnet subagent:
{
"agentType": "codex:codex-rescue",
"description": "Repair backup script: fix checksum path, add progress output, populate empty folders"
}OMC recorded the mission starting at 2026-08-07T17:40:16.986Z and completing at 17:40:49.962Z. The parent session ended at 17:41:03.946Z.
I could not recover the deleted parent transcript, so I cannot prove what upstream text caused that unrelated task description to be generated. I can prove that Orca created the parent Claude session in its hidden rate-limit cwd and that the session made model/tool calls.
Behavior while Claude was already at its limit
At the time of the 82-session burst, Claude usage showed 100% used for the five-hour window. The repeated sessions produced limit notifications, but there was no new successful tool activity in ~/.claude/.session-stats.json during that specific 30-minute burst.
That suggests those attempts were rejected at the quota boundary. However, the same behavior after the quota reset could make successful calls again. The earlier 9cd4... session proves the PTY path can reach real inference and tools.
Steps to reproduce
- On macOS, install Orca v1.4.176 and authenticate Claude Code.
- Have ordinary Claude global hooks/plugins enabled. The problem does not require an Orca automation.
- Start Orca and focus/show/restore its main window so usage refresh runs.
- Let Claude usage fetching fall back to the PTY path.
- Inspect
~/.claude/session-env/*/sessionstart-hook-*.sh. - Observe new session IDs whose transcript paths contain
Library-Application-Support-orca-rate-limit-pty-cwd. - Put the Claude account at its five-hour limit and keep Orca focused.
- Observe repeated limit notifications and additional hidden session IDs.
- Monitor the process tree to see real
claudeprocesses spawned beneath Orca/its daemon.
Expected behavior
Background usage tracking must not create an inference-capable Claude session or load the user's hooks, plugins, MCP servers, project instructions, or tool permissions.
A usage probe must never:
- automatically accept a trust prompt;
- blindly press Enter without identifying the exact TUI state;
- allow text to become a normal model prompt;
- execute tools/subagents;
- retry in a way that creates many Claude sessions;
- consume the user's Claude subscription quota.
Suggested fixes
- Remove the interactive Claude PTY fallback for automated/background usage refresh. Prefer the OAuth usage endpoint and the existing live statusline usage feed.
- If the PTY fallback must remain, make it explicit/manual opt-in and provide a setting to disable it.
- Never auto-accept trust prompts in a background usage probe.
- Do not send Enter repeatedly. Require an exact, versioned TUI state before sending any input and fail closed otherwise.
- Launch probes with hooks/plugins/MCP initialization disabled and without dangerous permission flags.
- Add single-flight protection and persistent exponential backoff keyed by provider/account.
- Gate the path when Claude is disabled or when no managed/selected Claude account exists.
- Add a regression test proving that background usage refresh cannot create a Claude transcript/session or invoke model/tool hooks.
Related issues
- [Bug]: Orca creates ~/.claude during background usage refresh even when Claude is disabled #12181 — background usage refresh creates
~/.claudeeven when Claude is disabled. - [Bug]: Claude usage stuck on "Limited" — usage-endpoint 429 Retry-After ignored, retries keep the throttle alive #9616 — usage 429 handling and focus/restore retry behavior.
No credentials, auth files, or raw environment values are included in this report.
Activity
manuaudio commentedon Aug 8, 2026
Confirmed on current
main(940f2ff) — plus one gap worth addingVerified each anchor in the report against the tree, and found a fourth that explains the 82-session burst specifically.
Confirmed
src/main/rate-limits/claude-pty.tsy:/usage\rgoes out on a 2 s timer regardless of what the CLI is showing.The gap not in the report: no single-flight
fetchViaPtyis called straight fromfetchClaudeUsageViaCli(claude-fetcher.ts:474) with no in-flight guard anywhere insrc/main/rate-limits/—rg -n 'inflight|inFlight|singleFlight' src/main/rate-limitscomes back empty.So nothing prevents overlapping probes from each spawning their own
claudeprocess. That's the mechanism behind "82 session UUIDs in one 30-minute window" — it isn't only retry cadence, it's concurrent spawns with no mutual exclusion. Suggested fix 6 in the report is, I think, the highest-leverage one for that symptom.Offer
Happy to implement, but the eight suggestions span product decisions I shouldn't make unilaterally — 1 and 2 in particular (remove the fallback vs. make it opt-in) change behavior for anyone relying on the PTY path today.
The narrow one I'd start with is single-flight, since concurrent duplicate probes seem indefensible regardless of which direction you take the rest. One design question before I write it:
fetchViaPtyaccepts anAbortSignal, so sharing one in-flight promise means one caller's abort would cancel the probe for everyone. Do you want (a) shared promise, aborting only when every waiter has aborted, or (b) a plain "already running" guard where the second caller gets the first one's result and its signal only detaches it?Tell me which of the eight you want and I'll open a PR against it.
(Reported findings verified with Claude Opus 5; no code changes proposed in this comment.)
david-lai-jpg commentedon Aug 8, 2026
Thanks for confirming this against current
mainand finding the missing single-flight guard.For the abort design, please use (a): one internally owned probe per Claude runtime/account target, with per-caller waiters, and abort the underlying PTY only when every waiter has detached or aborted. The first caller's
AbortSignalshould not own a process shared by later callers.My requested priority is:
Single-flight is important containment, but it is not a complete fix for this report: one remaining probe can still inherit hooks/plugins, accept trust, misroute
/usage, and reach model/tool execution. I would keep the issue open until the blind-input path is removed or placed behind explicit opt-in.One regression case should install a fake Claude executable that presents an unexpected prompt. The test should prove Orca sends neither
ynor repeated Enter and exits without starting a second probe when multiple refreshes arrive.razankv13 commentedon Sep 5, 2026
I’m seeing the same issue. My Claude usage keeps increasing while Orca ADE is open, even though no Claude task or worker is visibly running. It looks like background usage checks are consuming quota without any user-started Claude work.
david-lai-jpg commentedon Oct 7, 2026
are you gonna address this issue? this has been going on for a few months now and it is really annoying - burning up my quota just to check my usage that is just plain dumb. i already gave you the solution to fix it. please fix it.
OrcaWin commentedon Oct 11, 2026
Thanks for the detailed report. This is fixed on main by #26801, which removed the hidden interactive Claude
/usagesession entirely, so usage refresh no longer starts a Claude process.