Symptom
agentworkforce deploy (cloud mode) with the oauth harness source produces deployments with empty credentialSelections, so ctx.llm is a stub on every fire:
error: "ctx.llm is unavailable: set persona.useSubscription:true and connect a provider, or pass a …"
Live repro 2026-06-04: linear-chat-lead redeployed via CLI → deployment d618a202 had credentialSelections: {} despite connected provider credentials; only the WEB wizard stamps OAuth selections (cloud#1878 active-credential default).
Root cause (packages/deploy/src/modes/cloud/index.ts)
Two legs share the hole — only the byok and plan paths stamp selections:
ensureCloudSubscriptionReady oauth leg: await ensureSubscriptionOauth(args); return { provider }; — no credentialSelections.
ensureHarnessReady oauth leg: await ensureHarnessOauth(args); return {}; — same gap for non-subscription personas.
Compounding it: deriveModelProvider maps e.g. model: 'gpt-5.5' → openai, so the CLI verifies the user's codex subscription ("openai credentials already connected") — a credential cloud's #1890 runtime-env resolution deliberately REJECTS (ChatGPT OAuth tokens are not platform API keys), so even stamping it would turn the stub into a failed delivery.
Fix shape
The lookup needs no new cloud endpoint: GET /api/v1/cloud-agents selects from provider_credentials and returns the row id — the CLI already parses this response in isHarnessOauthConnected. Caveat: the response harness field is harnessForModelProvider output (claude/codex/gemini/opencode), so matching must accept the alias pair, not bare equality with the model-provider string.
- Helper: look up the most-recent
status === 'connected' row whose harness matches the provider (alias-aware), return its id.
- anthropic oauth legs (both): stamp
credentialSelections: { anthropic: <id> }; if no row found, warn and return unstamped (today's behavior).
- openai (and any non-anthropic) oauth: do NOT stamp — print the actionable message: codex/ChatGPT subscriptions are harness-only;
ctx.llm needs --harness-source byok with a platform API key or an anthropic credential.
- (Follow-up candidate, separate decision) let
--harness-source oauth + a connected anthropic credential override deriveModelProvider's model-family pick so claude-capable personas with openai-default models can still get a working ctx.llm.
Context: cloud#1890 (oauth_token/provider_oauth runtime resolution), cloud#1878 (wizard default), cloud#1889/#1891 (runtime/env chain — all deployed and verified in prod today; the CLI stamp is the last client-side gap).
🤖 Generated with Claude Code
Symptom
agentworkforce deploy(cloud mode) with the oauth harness source produces deployments with emptycredentialSelections, soctx.llmis a stub on every fire:Live repro 2026-06-04: linear-chat-lead redeployed via CLI → deployment d618a202 had
credentialSelections: {}despite connected provider credentials; only the WEB wizard stamps OAuth selections (cloud#1878 active-credential default).Root cause (packages/deploy/src/modes/cloud/index.ts)
Two legs share the hole — only the
byokandplanpaths stamp selections:ensureCloudSubscriptionReadyoauth leg:await ensureSubscriptionOauth(args); return { provider };— nocredentialSelections.ensureHarnessReadyoauth leg:await ensureHarnessOauth(args); return {};— same gap for non-subscription personas.Compounding it:
deriveModelProvidermaps e.g.model: 'gpt-5.5'→openai, so the CLI verifies the user's codex subscription ("openai credentials already connected") — a credential cloud's #1890 runtime-env resolution deliberately REJECTS (ChatGPT OAuth tokens are not platform API keys), so even stamping it would turn the stub into a failed delivery.Fix shape
The lookup needs no new cloud endpoint:
GET /api/v1/cloud-agentsselects fromprovider_credentialsand returns the rowid— the CLI already parses this response inisHarnessOauthConnected. Caveat: the responseharnessfield isharnessForModelProvideroutput (claude/codex/gemini/opencode), so matching must accept the alias pair, not bare equality with the model-provider string.status === 'connected'row whoseharnessmatches the provider (alias-aware), return itsid.credentialSelections: { anthropic: <id> }; if no row found, warn and return unstamped (today's behavior).ctx.llmneeds--harness-source byokwith a platform API key or an anthropic credential.--harness-source oauth+ a connected anthropic credential overridederiveModelProvider's model-family pick so claude-capable personas with openai-default models can still get a working ctx.llm.Context: cloud#1890 (oauth_token/provider_oauth runtime resolution), cloud#1878 (wizard default), cloud#1889/#1891 (runtime/env chain — all deployed and verified in prod today; the CLI stamp is the last client-side gap).
🤖 Generated with Claude Code