feat(generate): add Codex editor support#72
Conversation
- New generateCodex(): writes AGENTS.md (shared orchestrator+skills logic)
and .codex/config.toml with MCP servers translated to Codex's TOML format
- Codex does not expand ${env:VAR} inside [mcp_servers.<id>.env] (unlike
Claude/Cursor); host env vars are forwarded via env_vars instead
- Register 'codex' in the generators map (hub generate -e codex)
- Gracefully skip MCPs with no url/image/package instead of crashing
(caught via manual testing against a real hub.config.ts)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 11 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe ChangesCodex generator
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant HubCLI
participant generateCodex
participant ProjectFiles
HubCLI->>generateCodex: invoke Codex generation
generateCodex->>ProjectFiles: write .codex/config.toml
generateCodex->>ProjectFiles: update AGENTS.md
generateCodex->>ProjectFiles: refresh managed .gitignore
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/cli/src/commands/generate.ts (1)
2324-2340: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDocker branch re-implements placeholder logic; reuse
splitEnvForCodex.Lines 2326-2333 re-run
ENV_PLACEHOLDERindependently to decide-e KEYvs-e KEY=value, duplicating (and inheriting the same cross-name gap as)splitEnvForCodex. Deriving the docker-eflags from the already-computedforwarded/literalsets keeps the two paths consistent.♻️ Reuse split results for docker -e flags
if (mcp.image) { const args = ["run", "-i", "--rm"]; - for (const [key, value] of Object.entries(mcp.env ?? {})) { - const match = ENV_PLACEHOLDER.exec(value); - if (match && match[1] === key) { - args.push("-e", key); - } else { - args.push("-e", `${key}=${value}`); - } - } + for (const key of forwarded) { + args.push("-e", key); + } + for (const [key, value] of Object.entries(literal)) { + args.push("-e", `${key}=${value}`); + } args.push(mcp.image); lines.push(`command = 'docker'`, `args = ${tomlArray(args)}`);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/commands/generate.ts` around lines 2324 - 2340, Update the Docker branch in the MCP command generation flow to derive its `-e` arguments from the existing `forwarded` and `literal` results produced by `splitEnvForCodex`, rather than re-running `ENV_PLACEHOLDER` over `mcp.env`. Preserve `-e KEY` for forwarded variables and `-e KEY=value` for literal variables so Docker and Codex use consistent environment classification.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/commands/generate.ts`:
- Around line 2289-2312: Update splitEnvForCodex to detect any ${env:VAR}
placeholder, including lowercase names and placeholders whose name differs from
the target key, before classifying entries as literal. Warn or reject those
unsupported placeholders instead of writing them into the Codex env map
literally, while preserving forwarding for valid matching placeholders.
- Around line 2317-2320: Update the URL branch in the MCP serialization logic to
emit the configured bearer-token environment variable before returning. Ensure
URL-based MCPs preserve their authentication configuration while retaining the
existing URL output and return behavior.
---
Nitpick comments:
In `@packages/cli/src/commands/generate.ts`:
- Around line 2324-2340: Update the Docker branch in the MCP command generation
flow to derive its `-e` arguments from the existing `forwarded` and `literal`
results produced by `splitEnvForCodex`, rather than re-running `ENV_PLACEHOLDER`
over `mcp.env`. Preserve `-e KEY` for forwarded variables and `-e KEY=value` for
literal variables so Docker and Codex use consistent environment classification.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 949ee15f-7036-4a47-b811-d8618c09264d
📒 Files selected for processing (1)
packages/cli/src/commands/generate.ts
| if (mcp.url) { | ||
| lines.push(`url = ${tomlString(mcp.url)}`); | ||
| return lines.join("\n"); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Codex CLI config.toml mcp_servers url streamable http bearer_token_env_var
💡 Result:
In the Codex CLI, support for bearer_token (as a plain-text string) in config.toml has been deprecated and removed in favor of bearer_token_env_var [1][2]. The runtime now rejects the bearer_token field to prevent storing sensitive secrets in clear text on disk [3][4][2]. For streamable HTTP MCP servers, you must use bearer_token_env_var to specify an environment variable name from which the CLI will securely read the token at runtime [5][6]. Configuration Example: [mcp_servers.my-server] url = "https://mcp.example.com/mcp" bearer_token_env_var = "MY_SECRET_TOKEN_ENV_VAR" Key details: - Mechanism: When configured, the CLI reads the value from the specified environment variable and sends it as an Authorization: Bearer <token> header [3][7]. - CLI Usage: When adding a server via the CLI, use the --bearer-token-env-var flag [3][8]: codex mcp add my-server --url https://mcp.example.com --bearer-token-env-var MY_SECRET_TOKEN_ENV_VAR - Troubleshooting: If you are encountering errors, ensure you are not using the bearer_token field in your config.toml, as it is unsupported and will trigger validation errors, even if it appears in some legacy documentation or generated schemas [1][2]. Use mcp_servers (snake_case) for the configuration table [7].
Citations:
- 1: bearer_token for streamable_http MCP server openai/codex#5011
- 2: Config schema exposes unsupported MCP
bearer_tokenfield openai/codex#19275 - 3: openai/codex@a43ae86
- 4: [MCP] Add support for streamable HTTP MCP servers openai/codex#4317
- 5: https://developers.openai.com/codex/mcp
- 6: https://codex.danielvaughan.com/2026/05/19/codex-cli-mcp-server-management-cli-commands-oauth-streamable-http-production-patterns/
- 7: https://policylayer.com/integrations/codex
- 8: https://openai-codex.mintlify.app/configuration/mcp-servers
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the generator and any MCP config/schema definitions
git ls-files | rg '(^|/)(generate|mcp|config).*\.(ts|js|json|md)$|config\.toml|mcp_servers'
# Inspect the relevant area around the cited lines
sed -n '2285,2345p' packages/cli/src/commands/generate.ts
# Search for URL/bearer/env handling in the CLI source
rg -n "bearer_token_env_var|bearerTokenEnvVar|mcp\.env|mcp_servers|url =" packages/cli/src -g '!**/dist/**' -g '!**/build/**'
# Search for schema/docs mentions that might clarify intended behavior
rg -n "bearer_token_env_var|streamable http|mcp_servers|Authorization: Bearer|env" packages/cli -g '!**/dist/**' -g '!**/build/**' -g '!**/node_modules/**'Repository: arvoreeducacao/rhm
Length of output: 21442
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the exact implementation around the URL branch and any preceding env handling
python3 - <<'PY'
from pathlib import Path
p = Path('packages/cli/src/commands/generate.ts')
text = p.read_text()
for start in [2250, 2290, 2310, 2330]:
lines = text.splitlines()
print(f"\n--- {start} ---")
for i in range(start-1, min(len(lines), start+40)):
print(f"{i+1}: {lines[i]}")
PY
# Look for the MCP config type/shape if declared in this repo
rg -n "type .*MCP|interface .*MCP|bearer_token_env_var|env:" packages/cli/src packages/cli -g '!**/dist/**' -g '!**/build/**' -g '!**/node_modules/**'
# Find any docs/examples for url-based MCPs
rg -n "mcp_servers.*url|url = \".*mcp|bearer_token_env_var" . -g '!**/dist/**' -g '!**/build/**' -g '!**/node_modules/**'Repository: arvoreeducacao/rhm
Length of output: 13806
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the MCP config type and any docs/examples around URL-based MCPs
sed -n '1,120p' packages/cli/src/core/hub-config.ts
# Read the part of generate.ts that builds Codex MCP blocks for comparison with other targets
sed -n '2380,2415p' packages/cli/src/commands/generate.ts
# Search for Codex MCP schema references in docs or examples
rg -n "bearer_token_env_var|env_vars|mcp_servers\\.<id>|mcp_servers\\.|streamable http|streamable-http|Authorization: Bearer|MCPConfig" packages/cli website -g '!**/dist/**' -g '!**/build/**' -g '!**/node_modules/**'Repository: arvoreeducacao/rhm
Length of output: 9481
Emit bearer_token_env_var for URL MCPs. The url branch returns before writing auth config, so streamable HTTP MCPs lose their bearer-token env and won’t authenticate.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/commands/generate.ts` around lines 2317 - 2320, Update the
URL branch in the MCP serialization logic to emit the configured bearer-token
environment variable before returning. Ensure URL-based MCPs preserve their
authentication configuration while retaining the existing URL output and return
behavior.
…ate-codex-editor # Conflicts: # packages/cli/src/commands/generate.ts
Addresses CodeRabbit review on PR #72: - splitEnvForCodex now detects any ${env:...} placeholder (including lowercase and name-mismatched) and warns instead of writing a literal that Codex won't expand - url MCPs with auth emit a warning (Codex needs bearer_token_env_var, which the hub schema has no source for) instead of silently dropping it - buildCodexMcpBlock returns { block, warnings }; caller logs warnings - export both functions and add generate.test.ts (14 unit tests)
The unit tests imported generate.ts, which imports @arvoretech/hub-core (a workspace dep only present once built). CI runs test:cov before the build step, so Vite could not resolve the import and the suite failed. Move the pure helpers (tomlString, tomlArray, splitEnvForCodex, buildCodexMcpBlock) into commands/codex-config.ts with no heavy deps; generate.ts imports from there and tests target the module directly.
O que
Adiciona um quinto editor ao
hub generate: Codex (OpenAI CLI), no mesmo padrão decursor/claude-code/kiro/opencode.Por quê
O Codex CLI lê
AGENTS.mdnativamente, mas o hub não tinha generator dedicado para ele — cada workspace precisava traduzir o.mcp.jsonmanualmente pro formato TOML do Codex (.codex/config.toml,[mcp_servers.<id>], snake_case, sem expansão de${ENV}).Mudanças
packages/cli/src/commands/generate.ts:generateCodex(config, hubDir)— geraAGENTS.md(reaproveitabuildOrchestratorRule+buildSkillsSection, mesma lógica do Claude Code) e.codex/config.tomlcom os MCP servers deconfig.mcpsbuildCodexMcpBlock— traduz cadaMCPConfigpro formato TOML do Codex:url→[mcp_servers.<id>]comurlimage→command = 'docker'+argspackage→command = 'npx'+args${env:VAR}noenv→env_vars = [...](Codex não expande${}; a var do host é encaminhada por nome)url/image/package→ pulado com warning (em vez de crashar — foi assim que encontrei o bug abaixo)upstreams) viabuildProxyUpstreams, mesmo padrão dos outros editorescodex: { name: "Codex", generate: generateCodex }no mapagenerators.codex/rules/persona.mdadicionado à seção de persona do.gitignoregeradoBug encontrado durante o teste manual
Rodei
hub generate -e codexcontra ohub.config.tsreal doarvore-hub(não só testes unitários) e o generator crashava: o MCPbeeusa{ command: "bee", args: [...] }, campos que não existem emMCPConfig(sópackage/url/image). Isso já quebrava silenciosamente nos outros generators (geravaargs: ["-y", undefined]); no Codex eu fiz falhar de forma explícita e recuperável — loga um warning e pula o MCP, em vez de crashar ogenerateinteiro.Como testei
pnpm build(tsup) — build OKpnpm lint(eslint) — limpopnpm test(vitest) — 22/22 passandonode_modules/@arvoretech/hub/distdo workspacearvore-hub(que tem os 20 MCPs reais, incluindo proxy e obeequebrado), rodeihub generate -e codex, validei o.codex/config.tomlresultante comtomllib.load(Python) — 13/14 servers traduzidos corretamente,beepulado com warning claroSummary by CodeRabbit
hub generatecommand.