diff --git a/apps/x/apps/renderer/src/components/onboarding/steps/llm-setup-step.tsx b/apps/x/apps/renderer/src/components/onboarding/steps/llm-setup-step.tsx
index 86787753..fa7ee93c 100644
--- a/apps/x/apps/renderer/src/components/onboarding/steps/llm-setup-step.tsx
+++ b/apps/x/apps/renderer/src/components/onboarding/steps/llm-setup-step.tsx
@@ -39,9 +39,14 @@ export function LlmSetupStep({ state }: LlmSetupStepProps) {
updateProviderConfig, handleTestAndSaveLlmConfig, handleTestAndAddAnother,
connectedFlavors, handleNext, handleBack,
upsellDismissed, setUpsellDismissed, handleSwitchToRowboat,
+ chatgpt,
} = state
const isMoreProvider = moreProviders.some(p => p.id === llmProvider)
+ // "Sign in with ChatGPT" (below the OpenAI card) is an alternative to a key:
+ // signing in counts as a connected provider alongside any saved BYOK one,
+ // which is what unlocks Continue when no API key was entered.
+ const hasConnectedProvider = connectedFlavors.size > 0 || chatgpt.status.signedIn
// Connect-only, mirroring Settings: entering a key (or base URL) is enough
// and the model is resolved silently at save. openai-compatible is the sole
// exception with a visible Model field — its /models endpoint often doesn't
@@ -188,6 +193,56 @@ export function LlmSetupStep({ state }: LlmSetupStepProps) {
)}
+ {/* ChatGPT subscription — OAuth sign-in shown under the OpenAI card,
+ mirroring Settings (settings-dialog.tsx, gated on provider ===
+ "openai"). Alternative to an API key: signs in via the shared
+ chatgpt:* path, independent of models.json (the Codex model client
+ consumes the token in core). */}
+ {llmProvider === "openai" && (
+