Skip to content

deploy/cloud: oauth harness legs never stamp credentialSelections — ctx.llm stubs on every CLI oauth deploy #196

Description

@khaliqgant

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.

  1. Helper: look up the most-recent status === 'connected' row whose harness matches the provider (alias-aware), return its id.
  2. anthropic oauth legs (both): stamp credentialSelections: { anthropic: <id> }; if no row found, warn and return unstamped (today's behavior).
  3. 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.
  4. (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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions