Skip to content

feat: add codex-oauth provider support for ChatGPT-authenticated Code…#87

Open
kikuchy wants to merge 1 commit into
tak848:mainfrom
kikuchy:feat/codex-app
Open

feat: add codex-oauth provider support for ChatGPT-authenticated Code…#87
kikuchy wants to merge 1 commit into
tak848:mainfrom
kikuchy:feat/codex-app

Conversation

@kikuchy

@kikuchy kikuchy commented May 14, 2026

Copy link
Copy Markdown

Why

Currently, ccgate requires explicit API keys for LLM providers. However, users who already have a ChatGPT subscription may prefer to use the Codex CLI's built-in OAuth authentication instead of provisioning and paying for a separate OpenAI developer API key. This change allows users to run ccgate using their existing ChatGPT subscription by leveraging the native Codex CLI session.

What

  • Adds support for a new codex-oauth LLM provider.
  • Implements a client that invokes the Codex CLI binary natively to perform permission classification using its authenticated session.
  • Adds codex_bin and codex_home configuration options to securely manage the Codex CLI execution environment without leaking existing environment variables.
  • Updates the JSON schemas (claude.schema.json and codex.schema.json) to support the new provider configurations.

(Also we can communicate with Japanese.)

@tak848 tak848 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together -- really nice to see a ChatGPT-plan path land on ccgate!

A handful of questions and small suggestions inline, all non-blocking. The biggest one is around project AGENTS.md potentially flowing into the classifier prompt; the rest are docs / comment polish and one latency open question. Happy to revisit any of them -- feel free to push back where you read it differently!

// Keep the managed ccgate CODEX_HOME self-contained. The file
// contains no secret, but mode 0600 matches the adjacent auth.json
// sensitivity and avoids leaking user configuration details.
if err := os.WriteFile(configPath, []byte("cli_auth_credentials_store = \"file\"\n"), 0o600); err != nil {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably the most interesting finding from my read! The managed config.toml only sets cli_auth_credentials_store = "file", with project_doc_max_bytes left at the Codex default (32 KiB). So Codex's agents_md.rs walks from the PermissionRequest cwd up to the project root and concatenates every AGENTS.md it finds into the first-turn instructions. The sandbox guards side effects (approvalPolicy=never, sandbox=read-only, networkAccess=false), but it does not guard against project-side prompts biasing the classifier verdict.

Would you consider appending project_doc_max_bytes = 0 to this initial template? In openai/codex codex-rs/core/src/agents_md.rs, both read_agents_md and agents_md_paths short-circuit when max_total == 0, so it is a clean disable, not a truncate.

Existing managed homes will not be re-written because the os.Stat check above already returns — totally fine, no migration needed. Users who already initialised the default home can edit the file manually (or delete it and let ccgate regenerate; auth.json is not touched).

// Keep the managed ccgate CODEX_HOME self-contained. The file
// contains no secret, but mode 0600 matches the adjacent auth.json
// sensitivity and avoids leaking user configuration details.
if err := os.WriteFile(configPath, []byte("cli_auth_credentials_store = \"file\"\n"), 0o600); err != nil {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious about this choice! Why pin file over keyring / auto? Would love a one-line note here so future readers do not switch it back. Best guess: keyring shares one OS service name with the user's regular ~/.codex login and would collide.

}
}

s, err := startAppServer(ctx, c.CodexBin, c.CodexHome)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open question on latency, not a blocker! Each Decide spawns a fresh app-server (initialize → account/read → thread/start → turn/start → wait turn/completed → kill). That is noticeably heavier than the other providers' single HTTP roundtrip. Would it be possible to include a metrics.jsonl excerpt (latency_ms) from a real session in the PR description so users can compare against anthropic / openai?

Two small adjacent levers worth noting:

  • turn/start does not pass a reasoning effort hint. If the Codex protocol accepts a low / minimal effort hint for classification, that could cut latency on reasoning-tier models.
  • docs/providers.md leaves the default model as "set explicitly". A documented recommended model for classification (mini-tier if available under the ChatGPT plan) would help users avoid landing on the most expensive option by accident.

Comment thread docs/providers.md
CODEX_HOME="${XDG_STATE_HOME:-$HOME/.local/state}/ccgate/codex-oauth/codex-home" codex login
```

Set `provider.codex_home` if you intentionally want to reuse another Codex profile, such as `~/.codex`. Set `provider.codex_bin` if `codex` is not on `PATH`. The child app-server process has `CODEX_API_KEY`, `OPENAI_API_KEY`, and `CCGATE_OPENAI_API_KEY` removed from its environment so this provider does not silently fall back to API-key billing.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two caveats that might be worth surfacing here for users who set provider.codex_home themselves (especially when pointing at ~/.codex):

  1. The managed default home gets cli_auth_credentials_store = "file" written automatically, but a self-managed home does not. Worth mentioning so users do not assume ccgate set it for them.
  2. Codex auto-loads AGENTS.md from both CODEX_HOME/AGENTS{,.override}.md (global) and from cwd up to the project root (project), concatenating them into first-turn instructions. To keep classification verdicts independent of whatever the user is running Codex / Claude Code for, recommend setting project_doc_max_bytes = 0 in the Codex config.toml, and avoiding AGENTS.md inside the CODEX_HOME being pointed at.

The second point also applies to the managed home (pairs with the suggestion on the client.go config template).

Comment thread docs/ja/providers.md
CODEX_HOME="${XDG_STATE_HOME:-$HOME/.local/state}/ccgate/codex-oauth/codex-home" codex login
```

普段使いの `~/.codex` などを意図的に再利用したい場合は `provider.codex_home`、`codex` が `PATH` にない場合は `provider.codex_bin` を設定します。`codex-oauth` の子プロセスからは `CODEX_API_KEY` / `OPENAI_API_KEY` / `CCGATE_OPENAI_API_KEY` を除去するため、API key 課金へ silent に落ちることはありません。

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same caveat as on docs/providers.md:48 — could you mirror it here as well?

  1. Managed default home gets cli_auth_credentials_store = "file" auto-written; self-managed codex_home does not — worth surfacing.
  2. Codex loads AGENTS.md from CODEX_HOME/AGENTS{,.override}.md (global) and from cwd up to repo root (project), concatenating them into first-turn instructions. Recommend project_doc_max_bytes = 0 in the Codex config.toml to keep classification verdicts independent of the user's normal Codex / Claude Code workflow context.

// Alternatives:
// name: 'openai', model: 'gpt-4o-mini', (env: OPENAI_API_KEY)
// name: 'gemini', model: 'gemini-2.0-flash', (env: GEMINI_API_KEY)
// name: 'codex-oauth', model: 'gpt-5.4', (ChatGPT OAuth via Codex app-server)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small suggestion! Could the example here use a mini-tier model? Classification needs deterministic structured output, not reasoning, so the cheapest model that supports outputSchema is likely the right default. Worth recommending the same in docs/providers.md too (currently "set explicitly").

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants