diff --git a/app/test/e2e/specs/runtime-picker-login.spec.ts b/app/test/e2e/specs/runtime-picker-login.spec.ts
new file mode 100644
index 000000000..f4addce72
--- /dev/null
+++ b/app/test/e2e/specs/runtime-picker-login.spec.ts
@@ -0,0 +1,340 @@
+// @ts-nocheck
+/**
+ * E2E test: Runtime picker → provider login → onboarding/home → logout.
+ *
+ * Exercises the *first-launch login funnel* end-to-end against the shared
+ * mock backend, running on the unified Appium chromium-driver session (CEF
+ * over CDP) — the same harness CI uses for Linux in `e2e/docker-compose.yml`.
+ *
+ * Phase 1 — Runtime picker (BootCheckGate ModePicker):
+ * 1. Reset to Welcome (no auth), then click "Select a Runtime" so
+ * Welcome dispatches `resetCoreMode()` and the BootCheckGate
+ * re-renders the picker.
+ * 2. Verify both runtime options ("Run Locally", "Run on the Cloud")
+ * plus the picker heading are present.
+ * 3. Cloud branch:
+ * - URL/token inputs appear when cloud is selected.
+ * - Empty URL on Continue → inline URL error.
+ * - Empty token → inline token error.
+ * - Unreachable host on "Test Connection" → unreachable status pill
+ * (no auth backend at 127.0.0.1:1 / picks a closed port).
+ * 4. Switch back to Local, click Continue. BootCheckGate runs `runBootCheck`
+ * against the embedded local core (which is already up — the e2e build
+ * seeds `VITE_OPENHUMAN_E2E_DEFAULT_CORE_MODE=local`) and we land back
+ * on Welcome with the OAuth provider row visible.
+ *
+ * Phase 2 — Provider login (deep-link bypass simulates the OAuth round-trip):
+ * 5. Welcome shows OAuth provider buttons. We don't click them (that opens
+ * the system browser), instead we simulate the post-OAuth deep link
+ * callback — exactly the same code path the real providers exercise
+ * when the backend redirects back to `openhuman://auth?token=...&key=auth`.
+ * 6. Walk onboarding (if shown) until we reach Home.
+ * 7. Verify mock backend recorded the auth/me profile fetch.
+ *
+ * Phase 3 — Logout:
+ * 8. Logout from Settings.
+ * 9. Confirm we're back on Welcome (logged-out state visible).
+ *
+ * The mock server (scripts/mock-api-*) handles auth + profile + onboarding.
+ * Deep links go through `window.__simulateDeepLink` so the spec is safe on
+ * the headless Linux container — no system browser, no real OAuth round-trip,
+ * and no PID-bound URL handler is touched.
+ */
+import { waitForApp, waitForAppReady, waitForAuthBootstrap } from '../helpers/app-helpers';
+import { triggerAuthDeepLinkBypass } from '../helpers/deep-link-helpers';
+import {
+ dumpAccessibilityTree,
+ hasAppChrome,
+ textExists,
+ waitForText,
+ waitForWebView,
+ waitForWindowVisible,
+} from '../helpers/element-helpers';
+import { supportsExecuteScript } from '../helpers/platform';
+import { resetApp } from '../helpers/reset-app';
+import {
+ logoutViaSettings,
+ waitForHomePage,
+ waitForLoggedOutState,
+ waitForRequest,
+ walkOnboarding,
+} from '../helpers/shared-flows';
+import {
+ clearRequestLog,
+ getRequestLog,
+ resetMockBehavior,
+ setMockBehavior,
+ startMockServer,
+ stopMockServer,
+} from '../mock-server';
+
+const LOG = '[RuntimePicker]';
+
+/**
+ * Click the smallest clickable element whose textContent contains `text`.
+ *
+ * Picker option tiles have a title + description nested in a single button so
+ * the button's textContent is `
` — strict equality misses.
+ * We score by descendant count to prefer the most-specific match (e.g. the
+ * Continue button text "Continue" matches several ancestors; we want the
+ *