Skip to content

runtime: codex-backend LlmContext leg — make OpenAI/ChatGPT subscriptions usable for ctx.llm #198

Description

@khaliqgant

Why

Operator expectation: "all subscription credentials should work" for ctx.llm. Today that's true for Anthropic (Claude Pro/Max access tokens are accepted by the Messages API with the OAuth beta header — the CLAUDE_CODE_OAUTH_TOKEN contract) but impossible for OpenAI via the platform API, probe-verified 2026-06-04 against a real codex subscription tokens.access_token:

  • POST api.openai.com/v1/chat/completions + subscription bearer → auth ACCEPTED, billing refused:
    {"error":{"message":"You exceeded your current quota...","type":"insufficient_quota","code":"insufficient_quota"}}
  • POST api.openai.com/v1/responses (the sign-in-with-ChatGPT path, tried gpt-5.5-codex and gpt-5.5) → scope-blocked:
    {"error":{"message":"You have insufficient permissions for this operation. Missing scopes: api.responses.write...","type":"invalid_request_error"}}

So cloud's resolver correctly refuses to inject these tokens as OPENAI_API_KEY (cloud#1890) — injecting one produces configured-then-insufficient_quota on every call, strictly worse than the explicit stub. The current mitigations are workarounds: anthropic cross-stamp for openai-family personas (workforce#197), house relay-managed key, or platform BYOK.

What

A third provider leg in packages/runtime/src/cloud-llm.ts that speaks the codex/ChatGPT backend protocol (what the codex CLI itself uses for subscription inference) instead of the platform API:

  1. New credential source recognized by selectCredential (e.g. CODEX_OAUTH_TOKEN / a structured env the cloud resolver can emit for provider_oauth + openai once this leg exists).
  2. The leg implements the codex backend session/completion exchange (endpoint, headers, account_id from the auth blob, streaming shape) and adapts it to the LlmContext interface.
  3. Token refresh: subscription access tokens expire in hours — compose with the existing refresh seam (cloud's refreshHarnessCliCredentialIfStale already refreshes openai blobs via auth.openai.com/oauth/token).
  4. Cloud follow-up (separate PR): lift the provider_oauth+openai rejection in resolveCredentialValue to emit the new env contract instead of throwing, and stamp openai-family selections in the deploy clients.

Open questions

  • Protocol stability/ToS: the ChatGPT backend API is not a published platform contract; assess maintenance risk before committing (the codex CLI's own implementation is the reference).
  • Model mapping: subscription backend serves codex-tuned models; resolveModel needs a mapping table rather than pass-through.

Context

cloud#1890 (rejection + rationale), workforce#196/#197 (selections stamping + cross-stamp fallback), probe transcript in the team channel 2026-06-04.

🤖 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