Repository navigation
Description
Summary
The mobile new-tab agent menu resolves the agent-detection host from repo.connectionId only. Runtime-hosted repos have connectionId: null, so they fall through to preflight.detectAgents, which runs on the paired host rather than on the runtime environment that owns the workspace. The menu then lists the paired host's installed agents; agents installed only on the runtime host never appear, and when the paired host has no agents at all the section is empty.
This is the mobile counterpart of #9370, which was fixed for desktop by #9790 (AgentsPane + QuickLaunchButton). The mobile loader was never extended, so it still has the SSH-only resolution that #9790 replaced.
Code references are from main @ c065a2d (2026-08-10).
Where it goes wrong
mobile/src/session/mobile-new-tab-agent-loader.ts declares a repo shape that cannot express runtime ownership:
// :11-14
type RuntimeRepoSummary = {
id: string
connectionId?: string | null
}and then branches on that field alone:
// :58-61
const connectionId = repo.connectionId?.trim() || null
return connectionId
? client.sendRequest('preflight.detectRemoteAgents', { connectionId })
: client.sendRequest('preflight.detectAgents') // runtime-hosted repos land hererepo.list returns full Repo rows (src/main/runtime/rpc/methods/repo.ts:109-114 → runtime.listRepos()), so the field that disambiguates this case is already on the wire — and its doc comment names this exact failure mode:
// src/shared/types.ts:269-273
/**
* Explicit execution owner for this repo. Runtime-host repos need this
* because they otherwise look identical to local repos (`connectionId: null`).
*/
executionHostId?: 'local' | `ssh:${string}` | `runtime:${string}` | nullDesktop resolves all three owners from that field:
// src/renderer/src/hooks/useAgentDetectionTarget.ts:53-60
const executionHost = parseExecutionHostId(getExecutionHostIdForWorktree(state, worktreeId))
if (executionHost?.kind === 'ssh') {
return `ssh:${executionHost.targetId}`
}
if (executionHost?.kind === 'runtime') {
return `runtime:${executionHost.environmentId}`
}
return AGENT_DETECTION_LOCAL_TARGET_KEYThe mobile loader has no runtime branch, and the fallback is silent — there is no signal distinguishing "the runtime host reports no agents" from "we asked the wrong host".
Steps to reproduce
- Run
orca serveon a headless host B and install an agent there that is not installed on your desktop A (e.g.pi). - On desktop A, register B as a Remote Orca Server environment and open a workspace that lives on B.
- Pair Orca Mobile (Android or iOS) to A.
- In the mobile app, open that workspace and tap
+to open the new-tab drawer.
Actual: the agent section lists A's installed agents. pi (installed only on B) is absent. If A has no agents installed, the section is empty.
Expected: the agent section lists the agents installed on B, matching what desktop A shows for the same workspace after #9790.
Note on the fix
The loader cannot fix this on its own. preflight.detectAgents takes no params (src/main/runtime/rpc/methods/preflight.ts:28-31, params: null) and mobile's RpcClient addresses only the single paired host (mobile/src/transport/rpc-client.ts:972), so there is currently no way for mobile to target a specific runtime environment. Desktop sidesteps this because its renderer dials each environment directly (src/renderer/src/store/slices/runtime-detected-agents.ts:69-72 via callRuntimeRpc({ kind: 'environment', environmentId })).
Making mobile correct therefore needs a host-side delegation step. The transport already exists — callRuntimeEnvironment(userDataPath, selector, method, params, ...) (src/main/ipc/runtime-environment-transport-routing.ts:78) — but rpc/methods/ does not currently perform environment delegation anywhere (no userDataPath usage in that layer), so which layer should own it, how to prevent delegation loops, and whether a mobile client may name an arbitrary environment all look like maintainer calls rather than something to settle in a drive-by patch. Filing this instead of a PR for that reason.
Two smaller things worth folding in whatever the shape of the fix:
executionHostIdshould be added toRuntimeRepoSummaryand preferred overconnectionId, so the resolution cannot drift from desktop again.- Any failure in the loader currently blanks the whole section:
loadMobileNewTabAgentOptionsthrows on arepo.list/settings.getfailure or onworktree_repo_not_found(mobile-new-tab-agent-loader.ts:29-34, 55-57), and the call site maps that to an empty list (mobile/app/h/[hostId]/session/[worktreeId].tsx:3747-3751). A wrong-host result and a hard failure are indistinguishable to the user.
Existing coverage in mobile/src/session/mobile-new-tab-agent-loader.test.ts has only the floating-workspace (local) and SSH cases — a runtime-owned case would be the natural regression test.
Related
- [Bug]: New-tab agent menu lists locally installed agents for remote (runtime-hosted) workspaces #9370 — desktop new-tab menu listed local agents for runtime-hosted workspaces (closed as a duplicate of a consolidated investigation)
- fix(agents): scope Settings agent list and quick-launch menu to the remote-server host #9790 — fixed the desktop surfaces (
AgentsPane,QuickLaunchButton) - fix(tab-bar): detect new-tab menu agents on the host that owns the workspace #9373 — open PR extracting the shared desktop resolution hook
- [Feature]: mobile app new tab button should have the agent presets #3290 / Add mobile new-tab agent presets #3334 — added agent presets to the mobile new-tab drawer in the first place
- [Bug][Mobile]: Remote Orca servers show 0 worktrees when paired directly; Mac multi-env list only shows local (notification deep-link still opens workspace) #11869 — mobile not surfacing remote runtime workspaces (same "mobile can't see the runtime host's data" family)
Activity
AmethystLiang commentedon Aug 11, 2026
thanks for reporting. looking into it
AmethystLiang commentedon Aug 11, 2026
thanks for reporting. looking into it
OrcaWin commentedon Aug 12, 2026
Implemented in PR #13977: #13977
Mobile new-tab agent detection now follows the workspace execution owner: runtime-hosted repos proxy detection to the registered runtime, SSH repos use the SSH target, and local repos stay on the paired host. The new optional RPC preserves mixed-version behavior by falling back to the previous paired-host detection when an older host reports the method unavailable.
Focused host/mobile tests, Node and mobile typechecks, static analysis, packaging, Git compatibility, and cross-version wire checks pass. The full mobile job is blocked by an unrelated existing
mobile-create-pr-actionBitbucket expectation that fails identically against unchanged base code; it was reproduced locally and the failed job was rerun.