npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ytechai/codex-forge

v0.1.45

Published

Local all-model BYOK configuration forge for Codex Desktop and CLI. Single install supports both server mode and CLI tool mode.

Readme

codex-forge

Local BYOK model gateway for Codex Desktop & CLI

把任意 OpenAI / Anthropic 兼容模型接入 Codex 原生选择器,而无需重建 Codex。

codex-forge is a local Node.js gateway that speaks the OpenAI Responses API Codex expects, then routes each request to the right upstream: OpenAI Chat Completions, Anthropic Messages, generic OpenAI-style chat endpoints, or the ChatGPT/Codex backend when a valid token is available.

这套方案的目标很明确:保持 Codex 原生的编辑器/代理体验,同时把模型路由、BYOK 配置和订阅透传放到本地可控的层级里。它适合这样一类用户:

  • 想在 Codex 原生选择器里使用自有或 BYOK 模型;
  • 想保留函数调用、工具输出、流式响应和图像能力;
  • 想在本地控制 provider、routing 和 prompt 处理;
  • 想把 codex-forge 作为本地网关或远程服务端部署。

这个项目的实现很轻:纯 Node.js、零运行时依赖,跨平台支持 macOS、Windows、Linux、WSL 和 Git Bash。macOS 上唯一的专属能力是可选的 Desktop 选择器 ASAR 补丁,仅在 Codex 隐藏自定义条目时才需要。

已在 Codex Desktop 0.133.0-alpha.1(macOS arm64)上测试通过。


它能给你带来什么

Codex Desktop 只显示其服务端配置允许的模型。如果你有想作为一等公民出现在选择 器里的 OpenAI / Anthropic / Z.ai / DeepSeek / Gemini / OpenRouter / 本地代理 模型,本项目可以在本地把它们接入。

实际收益是:Codex 保持原生体验,而模型路由下沉到本地:

  • BYOK 模型出现在正常的 Codex 选择器里。 不需要重建 Codex,也不需要请求重 放工作流。
  • 原生 Codex agent 循环保持完整。 函数调用、工具输出、推理块、支持图像的 模型、shell 命令元数据和流式 SSE 都被翻译,而不是被压平成纯文本。
  • ChatGPT/Codex 透传。 如果 ~/.codex/auth.json 里有有效的 Codex 访问令 牌,forge 可以把 Codex 原生的 /v1/responses 流量以当前 Codex 构建使用的 gpt-5.5 slug 路由到 ChatGPT 的 Codex 后端。
  • Auto Router(可选)。 增加一个 Auto (smart routing) 选择器条目,用一 个便宜的分类器模型把每个任务路由到能胜任的最便宜模型 —— 简单轮次保持低成 本,困难轮次自动升级。见 docs/AUTO_ROUTER.md。
  • 提示词捕获/代理友好架构。 在 forge 前面放一个本地代理,可以去重模板文 本、注入稳定指令、修复伪工具文本,或在请求到达上游前按策略路由提示词。
  • 维护者在真实编码 agent 任务上的收益。 在维护者的内部 Codex 任务中, ChatGPT 透传加上 forge 前面的提示词捕获代理,带来了计费输入 token 的数倍下 降和相对基线路径明显更快的墙钟时间。仓库尚未附带可复现的基准脚本,请把这 当作轶事数据 —— 下面的基准章节说明了如何在引用数字前用明确的对照组测量 你自己的配置。

环境要求

  • Node.js 22+。
  • 已安装并完成认证的 Codex CLI/Desktop。
  • server 主机满足以下之一:
    • ~/.codex-forge/server/models.toml 中配置了 BYOK/上游模型;
    • server 通过 --settings 传入另一份 models.toml;
    • server 主机 ~/.codex/auth.json 中包含 tokens.access_token(仅用于 ChatGPT/Codex 透传)。
  • forge 只使用 Node.js 标准库与一个 TOML 解析器(smol-toml);如从源码运行, 请先执行 pnpm install 安装依赖。
  • Windows:PowerShell/cmd 可通过 node src/run.mjs ... 运行;WSL 或 Git Bash 仅在需要可选的 bin/ shell 包装脚本时才需要。
  • 仅 macOS:如果需要可选的 Desktop 选择器补丁,需要 npx 和 codesign。

安装

这是一个 Multi-binary package(@ytechai/codex-forge),安装后提供两个独立命令:

| 命令 | 职责 | 运行位置 | |---|---|---| | codex-forge-cli | 工具端:Codex 配置管理、模型切换、诊断 | 安装 Codex 的电脑 | | codex-forge-server | 服务端:模型代理、API 端点、daemon 管理 | 本机或局域网任意主机 |

两个命令来自同一个 npm 包,但运行时只通过 HTTP 协作。跨主机是默认架构约束; 同机只是 server 地址恰好为 loopback 的特例。 codex-forge-cli 与 codex app 同主机时可以共享本地 ~/.codex/config.toml,但 codex-forge-server 不读取、 不写入这份文件,也不控制 Codex Desktop。

方式一:npm 全局安装(推荐)

npm install -g @ytechai/codex-forge

安装后即可使用 codex-forge-cli 和 codex-forge-server 两个命令。

方式二:软链(开发/本地安装)

克隆仓库并把 bin/ 软链到 PATH 中,可直接使用最新代码:

git clone https://github.com/veryben/codex-forge ~/codex-forge
cd ~/codex-forge
pnpm install          # 安装 TOML 解析器依赖(smol-toml)
mkdir -p ~/.local/bin
ln -sf "$PWD/bin/codex-forge-cli" ~/.local/bin/codex-forge-cli
ln -sf "$PWD/bin/codex-forge-server" ~/.local/bin/codex-forge-server

bin/ 脚本是薄壳,优先加载 dist/,回退 src/。开发时可以设置 CODEX_FORGE_DEV=1 直接使用 src/,无需每次 npm run build:

export CODEX_FORGE_DEV=1    # 加入 ~/.zshrc 即可永久生效

移动仓库位置后需重建软链。在原生 Windows PowerShell/cmd 上直接运行:

git clone https://github.com/veryben/codex-forge $HOME\codex-forge
cd $HOME\codex-forge
pnpm install          # 或 npm install
node src/run.mjs show

如果找不到命令,确认 ~/.local/bin 在 PATH 中:

export PATH="$HOME/.local/bin:$PATH"
# 永久生效:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc  # macOS 默认 zsh

运行模式与命令

codex-forge 采用服务端 + 工具端分离架构,单一安装支持两种运行模式:

┌─────────────────────────────────────────────────────────────────┐
│  工具端 (codex-forge-cli)                                      │
│  运行位置: 安装 Codex 的电脑                                     │
│  职责: Codex 配置、本地 catalog、模型切换、启动 Codex             │
│  依赖: 必须连接运行中的服务端                                    │
└─────────────────────────────────────────────────────────────────┘
         │                              ▲
         │ 调用 API                     │ 获取数据
         ▼                              │
┌─────────────────────────────────────────────────────────────────┐
│  服务端 (codex-forge-server)                                    │
│  运行位置: 本机或其它电脑                                        │
│  职责: 模型配置、凭据、路由、翻译、daemon 生命周期                │
└─────────────────────────────────────────────────────────────────┘

服务端命令(服务运行)

运行位置:可以是本机或其它电脑,只需 ~/.codex-forge/server/models.toml

codex-forge-server start             # 后台启动守护进程
codex-forge-server stop              # 停止服务
codex-forge-server restart           # 重启服务
codex-forge-server status            # 查看服务状态
codex-forge-server logs              # 查看 server 日志
codex-forge-server console           # 前台运行(阻塞控制台)

前台运行时可指定参数:

codex-forge-server console --settings ~/.codex-forge/server/models.toml --port 58767
CODEX_FORGE_TOKEN=... codex-forge-server console --host 0.0.0.0 --port 58767

server 默认绑定 127.0.0.1。绑定 0.0.0.0 或其它局域网地址属于显式开启远程 访问,建议同时设置 CODEX_FORGE_TOKEN、防火墙规则,或在 TLS 反向代理后面部署。

服务端 API

| 端点 | 方法 | 用途 | |------|------|------| | /health | GET | 健康检查 | | /api/models | GET | 返回模型列表(简化版) | | /api/models/full | GET | 返回 CLI 生成 catalog 所需的模型 DTO | | /api/refresh | POST | 校验并刷新 server 配置,不写任何文件 | | /v1/models | GET | OpenAI 格式模型列表 | | /v1/chat/completions | POST | OpenAI chat 请求代理 | | /v1/messages | POST | Anthropic messages 请求代理 | | /v1/responses | POST | OpenAI responses 请求代理 | | /api/switch | POST | 已迁移到 CLI,返回 410 Gone |


工具端命令(工具操作)

运行位置:必须在安装 Codex 的电脑上,需要修改 ~/.codex/config.toml

通用选项

codex-forge-cli -v                       # 显示版本
codex-forge-cli --version                # 显示版本
codex-forge-cli -h                       # 显示帮助
codex-forge-cli --help                   # 显示帮助

服务端同样支持版本与帮助:

codex-forge-server -v                # 显示版本
codex-forge-server --help            # 显示帮助

配置管理

codex-forge-cli config show              # 查看当前服务器连接配置
codex-forge-cli config set host <ip>     # 设置远程服务器地址
codex-forge-cli config set port <port>   # 设置服务器端口

运行时状态按归属角色存放在 ~/.codex-forge/server/(仅 server 主机)与 ~/.codex-forge/cli/(仅 client 主机)两个子目录,没有扁平的旧布局需要迁移。

配置存储在 ~/.codex-forge/cli/cli.json,也可用命令行参数临时覆盖:

codex-forge-cli --host 192.168.1.100 --port 58767 list

当 Codex 已启用 forge 配置时,config set 会立即同步 ~/.codex/config.toml 里的 base_url(服务器在线则完整重建配置,离线则就地更新 base_url),无需 重新运行 enable。

模型操作

codex-forge-cli list                     # 查看可用模型列表
codex-forge-cli model list               # 同上
codex-forge-cli model current            # 查看当前使用的模型
codex-forge-cli model use <slug>         # 切换默认模型

Codex 配置

codex-forge-cli generate                 # 生成配置目录(需要服务运行)
codex-forge-cli enable                   # 启用 forge provider(修改 ~/.codex/config.toml,需要服务运行)
codex-forge-cli disable                  # 禁用 forge provider(恢复原配置)
codex-forge-cli doctor                   # 诊断配置问题

启动 Codex

codex-forge-cli codex -- "prompt"        # 使用 Codex CLI 执行任务
codex-forge-cli app .                    # 启动 Codex Desktop
codex-forge-cli app -m <slug> .          # 启动 Codex Desktop 并指定模型

配置文件说明

运行时状态按归属角色拆成两个子目录;codex-forge 默认跨主机部署,所以一台只 运行单一角色的机器只会出现对应角色的子目录:

  • ~/.codex-forge/server/:只存在于 server 主机 —— provider 配置、daemon 状态、日志、调试转储、迁移备份。
  • ~/.codex-forge/cli/:只存在于 client 主机 —— CLI 连接配置、Codex 模型 目录、备份。

每个路径只有一个归属位置,没有旧布局的等价副本,也没有回退解析。

| 文件 | 用途 | 读取者 | 写入者 | |------|------|--------|--------| | ~/.codex-forge/server/models.toml | 定义可用模型和上游 API(推荐,仅 server 主机) | 服务端 | 用户 | | ~/.codex-forge/cli/cli.json | 工具端连接 server 的 host / port / token(仅 client 主机) | 工具端 | 工具端(自动生成) | | ~/.codex-forge/cli/model_catalog.custom.json | Codex 模型目录(仅 client 主机) | Codex | 工具端生成 | | ~/.codex/config.toml | Codex provider 配置 | Codex | 工具端生成 | | ~/.codex-forge/cli/backups/config.toml.before-codex-forge | 首次 enable 前的 ~/.codex/config.toml 原样快照 | 工具端 | 工具端(仅首次) | | ~/.codex-forge/server/server.pid | daemon PID(仅 server 主机) | server | server | | ~/.codex-forge/server/server.log | daemon stdout / stderr(仅 server 主机) | server | server |

托管块的写入安全

enable / disable 只增删自己的托管块(# >>> codex-forge managed >>> … # <<< codex-forge managed <<<),并且:

  • 首次 enable 会把当时的 ~/.codex/config.toml 原样存成 ~/.codex-forge/cli/backups/config.toml.before-codex-forge。只在配置里还没有 托管块时写一次;后续 enable 不会用「已被 forge 改过」的内容覆盖它, disable 也不会删除它,留作随时可回退的原稿。
  • 如果发现别人的配置落在托管块标记内部(Codex Desktop 追加的 [desktop]、 [marketplaces.*]、[plugins.*] 等曾出现过这种情况),这些内容会被移出 托管块并重新输出,而不是被一起删掉;命令会在 stderr 打印被保留的内容。
  • enable 是幂等的:重复执行不会重复追加,也不会产生 diff。

这条角色边界还有静态保证:tests-node/architecture.test.mjs 会检查 server 代码 不得引用 cli/ 路径,client 代码不得引用 server 运行时产物(pid / log / debug)。


Windows 支持

可以,forge 在 Windows 上可用。核心 forge 是 Node.js,绑定 127.0.0.1,写入与 macOS/Linux 相同的 Codex provider 配置。可选以下任一方式:

| 环境 | 状态 | 说明 | |---|---|---| | 原生 Windows PowerShell/cmd | 支持 | 在仓库目录运行 node src/run.mjs ...。 | | WSL | 支持 | 与 Linux 相同。当 Codex CLI/Desktop 也在 WSL 中驱动时最合适。 | | Git Bash | 支持 | Node/Codex 在 PATH 上时可配合 POSIX bin/ 包装脚本使用。 | | PowerShell/cmd 中的 bin/ 脚本 | 非原生 | bash 脚本不可用;脚本会检测到非 bash 环境并给出明确提示,请改用 Git Bash 或 node src/run.mjs ...。 | | patch-app / restore-app | 仅 macOS | 它们针对 /Applications/Codex.app 与 macOS 上的 Electron ASAR 签名。 |

原生 Windows 快速检查:

node src/run-server.mjs --port 58767
node src/run.mjs show
node src/run.mjs list

路径行为刻意保持常规:

  • 在原生 Windows 中,~/.codex-forge/server/models.toml 指 %USERPROFILE%\.codex-forge\server\models.toml,Codex 配置 位于 %USERPROFILE%\.codex\config.toml。
  • 在 WSL 中,~/.codex-forge/server/models.toml 和 ~/.codex/config.toml 位于 Linux home 目录内,除非你显式用 --settings 指向 /mnt/c/... 下的 Windows 路径。
  • 不要把 WSL 生成的 ~/.codex/config.toml 与原生 Windows Codex 混用并指望两 者自动共享文件。如果 Codex 是原生 Windows,请走原生 Windows 安装路径,或手 动保持 Windows 配置同步。
  • 本地 provider URL 仍然是 http://127.0.0.1:58767/v1。

运行 forge 服务器并不需要可选的 macOS 选择器补丁。在 Windows 上,只要 Codex 能 读取生成的目录/provider 配置,请求就会像其他平台一样通过同一个本地端点路由。

Windows Store/MSIX 版 Codex Desktop 比 CLI 更严格。它可能把自定义本地/BYOK slug 视为不可用、把 model = "<custom-slug>" 改回 gpt-5.5,并在启动时添加 [tui.model_availability_nux] 条目。这是 Desktop 的允许列表行为,不是 forge 路 由行为:codex exec、TUI 和 forge 端点仍然使用配置的模型 slug。macOS 的 patch-app 助手不适用于 C:\\Program Files\\WindowsApps 下的 MSIX 包。

如果 Windows 有 Clash/V2Ray 之类的系统代理,请确保回环地址绕过它:

setx NO_PROXY "127.0.0.1,localhost,::1"
setx no_proxy "127.0.0.1,localhost,::1"

codex-forge-cli codex -- ... 和 codex-forge-cli app ... 会自动把这些回环条目加入 被启动进程的环境;如果你直接运行 codex.exe,也请全局设置它们。


快速开始

1. 生成目录并启动 forge

codex-forge-server start             # 后台启动守护进程
codex-forge-cli list                # 查看可用模型
codex-forge-cli show                # 查看状态

运行时文件按归属角色分开存放:server 主机的产物在 ~/.codex-forge/server/, client 主机的产物在 ~/.codex-forge/cli/:

~/.codex-forge/cli/model_catalog.custom.json   # model picker catalog for Codex(client 主机)
~/.codex-forge/cli/backups/                    # pre-forge config snapshot、session 迁移备份(client 主机)
~/.codex/config.toml                           # Codex provider config (CLI writes,client 主机)
~/.codex-forge/server/server.pid               # daemon pid(仅服务端读写,server 主机)
~/.codex-forge/server/server.log               # stdout/stderr + request summaries(server 主机)

服务器默认绑定 0.0.0.0,接受来自所有网络接口的连接。在不可信网络中,建议 配合 CODEX_FORGE_TOKEN 或防火墙使用。

2. 把 Codex Desktop 指向它

codex-forge-cli app .             # launch Codex Desktop with the forge wired in

app 会生成目录、按需启动本地守护进程,并在 ~/.codex/config.toml 写入一个 小的托管块,使 Codex Desktop 使用本地 provider。原配置会作为原样快照存到 ~/.codex-forge/cli/backups/config.toml.before-codex-forge(仅首次写入,disable 时保留),托管块可用以下命令移除:

codex-forge-cli disable

此后,Codex Desktop 能看到 ~/.codex-forge/server/models.toml 中的每个条目,外加 GPT-5.5 ChatGPT 透传 slug(当且仅当 ~/.codex/auth.json 持有有效的 tokens.access_token)。

如果你的 Codex Desktop 模型选择器只显示 default 且拒绝渲染目录条目,请使用 下面的 macOS 选择器补丁。

3. 切换 Desktop 的激活模型

codex-forge-cli model list
codex-forge-cli model use <slug>    # 切换到指定模型
codex-forge-cli app .               # 重新启动 Codex Desktop

codex-forge-cli model use <slug> 改写 ~/.codex/config.toml 中 forge 托管的块。

4. 不改配置使用 Codex CLI

一次性 CLI 运行使用内联 -c 覆盖,而不是修改 ~/.codex/config.toml:

codex-forge-cli codex -- "inspect this repo and summarize the architecture"

自定义配置文件

server 默认读取其主机上的 ~/.codex-forge/server/models.toml(仅支持这一种格式, JSON 配置已移除)。文件缺失时 server 仍会启动,只是没有 BYOK 模型可服务;此时若 server 主机 ~/.codex/auth.json 包含有效的 tokens.access_token,仍会返回 ChatGPT 透传模型。你也可以用 --settings 指向另一份 TOML:

codex-forge-server start --settings /path/to/my-models.toml

models.toml 结构(推荐)

一个网关一块:[providers.<id>] 写这个网关的凭据,[[providers.<id>.models]] 写该网关下的模型 —— 不用再写 provider = "…" 引用,也就不可能出现引用不存在的 网关:

[providers.deepseek]
protocol = "openai"        # openai | anthropic | ollama | generic-chat-completion-api
base_url = "https://api.deepseek.com"
api_key = "sk-…"           # 字面量,或 "${DEEPSEEK_API_KEY}" 在加载时展开
# api_key_env = "DEEPSEEK_API_KEY"   # 可选:环境变量名,优先于 api_key
# extra_headers = { x-foo = "bar" }  # 可选:网关级附加请求头

[[providers.deepseek.models]]
display_name = "my-deepseek-flash"  # 展示名 & slug 来源
model = "deepseek-flash"            # 上游真实模型 ID
max_context_limit = 819000

[providers.mimo-sk]
protocol = "anthropic"
base_url = "https://api.xiaomimimo.com/anthropic"
api_key = "sk-…"

[[providers.mimo-sk.models]]
display_name = "my-mimo-v2.5-sk"
model = "mimo-v2.5"
max_context_limit = 819000

完整示例见 examples/models-example.toml。

顺序即优先级:provider 块在文件中的顺序 × 块内模型顺序 = Codex 看到的模型 顺序(catalog priority、选择器顺序、以及"第一个可用模型"这个默认对话模型)。 想显式指定 Codex 辅助请求的落点,用 provider_default = true(见下节)。

旧写法(顶层 [[models]] + provider = "…",以及 [[models.<provider>]])会被 明确拒绝并给出正确写法,不会再静默读出 0 个模型。

设计要点:

  • provider 名即 ID(如 mimo-tp),允许同协议多网关、同网关多账号。
  • key 解析顺序:api_key_env → ${ENV} 展开 → 字面值;模型级 api_key 可覆盖 provider 的 key。
  • extra_headers 合并:provider 级与模型级按 key 合并,模型级优先。
  • 校验:模型嵌在 provider 块内,引用不存在的网关在结构上已不可能;缺 protocol / base_url 的 provider 其模型会被静默跳过。顶层出现 [[models]] 等旧写法会直接报错并给出正确写法。
  • 同名 model 跨网关由现有 slug 去重逻辑处理。

支持的 protocol 取值:

| protocol | 上游 API | |---|---| | openai | OpenAI /v1/chat/completions | | generic-chat-completion-api | OpenAI 形态的 chat completions | | anthropic | Anthropic /v1/messages | | ollama | 归一化为 generic-chat-completion-api |

forge 还在同一端口接受 Anthropic Messages 请求(/v1/messages)。对 于 openai 和 generic-chat-completion-api 模型,它把 Messages 请求翻译为 OpenAI 形态的 chat completions,并把响应转换回 Anthropic 形状。对于 anthropic 模型,它把请求带上配置的模型名直接透传到上游 /messages 端点。 该桥接支持文本、图像输入、基本函数工具/工具结果和流式 SSE。诸如提示词缓存、 extended thinking 签名、文件和 token 计数等 provider 特性仍取决于上游。

常用模型字段:

| 字段 | 行为 | |---|---| | display_name | 人类可读的选择器标签。 | | slug | 覆盖自动派生的 slug。 | | index | 排序值。 | | max_context_limit | 目录上下文窗口与压缩上限。 | | max_output_tokens | 翻译为 Anthropic 时的默认最大输出。 | | no_image_support | 为 true 时,目录声明仅文本输入。 | | supports_search_tool | 为 false 时目录关闭 web_search 工具。 | | provider_default | 指定 Codex 的 provider default(见下节);不写时取第一个模型。 | | extra_headers | 合并进请求的可选上游头(模型级优先)。 | | api_key / api_key_env | 罕见:覆盖 provider 的凭据(同网关分模型计费)。 |

Codex provider default(provider_default)

Codex 会把 catalog 条目按 priority 升序排序:数字最小的条目排在模型列表 第一位,并被当作 provider default —— 当 Codex 请求一个本网关没有的模型时, 它会回退到这个条目。Codex Desktop 自己的辅助请求就依赖这条回退路径:会话标题、 会话描述、turn 摘要、commit message / PR 文案、语音会话标题,都会先请求它内部的 模型 id(当前版本是 gpt-5.6-luna),BYOK 网关无法提供,于是落到 provider default 上。

因此:

  • 不写 provider_default 时,models.toml 的第一个模型是 provider default(与 codex-forge-cli enable 选默认对话模型的规则一致);
  • 想让这些辅助请求固定落到某个便宜模型(例如本机 Ollama 小模型),就在那一行 写 provider_default = true;
  • 该标记只影响 Codex 的辅助请求与模型列表排序,不会改变 ~/.codex/config.toml 里的对话模型;同一份文件里只有一个模型会生效 (重复标记时取第一个)。

codex-forge-cli list 会在对应行标注 (codex default)。

历史行为:priority 曾经按降序生成(1000 - index),使 models.toml 最后一行成为 provider default,辅助请求会被静默发到那个模型。如果因此 在日志里看到意外的模型(例如本机小模型)收到标题/摘要请求,请确认版本已包含 此修复,或用 provider_default 显式指定落点。

Codex 辅助请求的落点([aux])

先分清两个概念:

  • 模型别名(display_name / slug):同一个上游模型因为订阅计划、计费口径、 服务商不同而起的多个条目,例如 yj-mimo-v2.5-pro-tp 与 yj-mimo-v2.5-pro-sk 都指向 mimo-v2.5-pro;
  • helper id(本节):Codex Desktop 自己发起辅助请求时使用的内部模型 id (当前版本 gpt-5.6-luna,随桌面端版本变化),与你的模型别名无关。

会话标题、会话描述、turn 摘要、commit / PR 文案、语音会话标题都由 Codex Desktop 在临时 thread 里生成,它们总是请求上面那个内部 id。Codex 请求一个网关上不存在的 模型时会在客户端回退到 provider default(见上一节),服务端因此看不到这次请求, 也无法跟随你正在使用/切换的模型。

[aux] 段让 codex-forge 接管这类请求:

| 键 | 默认 | 行为 | |---|---|---| | enabled | true | 为 helper id 生成隐藏 catalog 条目(不出现在模型选择器)并按其路由;false 则交给 Codex 默认回退 | | helper_ids | ["gpt-5.6-luna"] | 覆盖内置的 helper id 列表 | | model | 不设置 | 设置时固定落到该 slug;不设置时跟随「该 Codex 安装最近一次实际使用的模型」(含会话内切换模型),没有记录时回退到 provider default |

[aux]
enabled = true
helper_ids = ["gpt-5.6-luna"]
# model = "yj-deepseek-flash"   # 可选:固定落点(便宜模型 / 固定计费口径)

跟随模式按 slug 记录,所以你在 -tp 计划与 -sk 计划之间切换时,辅助请求会跟着 切换,不会把两个计费口径混在一起;想固定到某个口径就直接 model = "yj-…-tp"。

codex-forge-cli list 会打印当前策略:

  aux: gpt-5.6-luna -> follows the model this install used last, else m-two

注意:

  • 「最近使用的模型」按 Codex 安装(x-codex-turn-metadata.installation_id)在内存里 记录,重启 server 后第一次辅助请求会先回退到 provider default;
  • 标题类辅助 thread 与你的会话没有父子关联,所以同时开着多个不同模型的会话时, 取的是最近一次使用过的那个;
  • helper_ids 由桌面端版本决定,未覆盖到的 id 仍然走 provider default(不会失效);
  • 隐藏条目的上下文窗口等元数据借用「它平时会落到的模型」,标题类请求很短,无实际影响。
  • 策略是确定性的:固定 → 最近使用 → provider default 三级;不做成本、阈值或" 自动挑便宜模型"之类的判断。

[router] / [[router.candidates]] 段与旧版 JSON 的 router 等价,只是换成 TOML 语法,详见 Auto Router。

Ollama / 本地 OpenAI 兼容 chat 端点

Codex 发送 Responses API。Ollama 和许多本地服务器暴露的是 OpenAI 形态的 /v1/chat/completions。保持 Codex 以 wire_api = "responses" 指向 forge;把 Ollama 配置为 generic-chat-completion-api,forge 就会做 Responses ⇄ chat completions 翻译:

[providers.ollama]
protocol = "ollama"        # normalized to generic-chat-completion-api
base_url = "http://127.0.0.1:11434/v1"
api_key = "ollama"

[[providers.ollama.models]]
display_name = "Ollama Llama 3.2"
model = "llama3.2"

protocol = "ollama" 在加载时会被归一化为 generic-chat-completion-api(provider 必须提供 base_url;缺失的 provider 会被跳过)。

重复运行 codex-forge-cli enable、codex-forge-cli app 和 codex-forge-cli model use ... 是幂等的:写入新托管块之前会先移除 forge 托管的顶层键和 [model_providers.codex_forge] 块,因此不会累积重复的 profile/provider 键。

Codex 可能会为其自身产品行为对 OpenAI 模型 slug(如 gpt-5.4-mini)发起小型 后台调用。这些不是 Ollama 路由故障;可用 forge 请求日志确认该 agent 轮次实际选 中的模型。


macOS 上 Codex Desktop 的选择器补丁

Codex Desktop 有一个 Statsig 服务端允许列表(use_hidden_models: true),会隐 藏所有 slug 不在硬编码列表里的模型。自定义目录条目落入隐藏桶,永远不会在选择 器中渲染。

一个单布尔值的 ASAR 补丁可以把允许列表分支关掉,让选择器只检查本地 hidden 标志(本目录从不设置该标志)。在较新的 Codex Desktop 构建中,补丁还会把本地最 近会话加载器从 modelProviders: null 改为 modelProviders: [],使 Desktop 经 由 codex_forge provider 路由时侧边栏仍能显示已有的原生 openai 会话。

组合补丁已在 macOS arm64 上的 Codex Desktop 26.519.41501 / codex-cli 0.133.0-alpha.1 测试通过。

打补丁前请备份 app.asar 和 Info.plist。

APP=/Applications/Codex.app
sudo cp -R "$APP" "$APP.unpatched-$(date +%Y%m%d-%H%M%S)"

# 1. Extract the ASAR
cd /tmp && rm -rf codex-asar-patch && mkdir codex-asar-patch && cd codex-asar-patch
npx --yes @electron/asar extract "$APP/Contents/Resources/app.asar" extracted

# 2. Patch the picker filter (single occurrence in tested builds)
PATCH_FILE=$(grep -RIl 'useHiddenModels' extracted/webview/assets/model-queries-*.js | head -n1)
sed -i.bak -E 's/let u=c\.useHiddenModels&&o!==`amazonBedrock`,d;/let u=!1,d;/' "$PATCH_FILE"
diff "$PATCH_FILE.bak" "$PATCH_FILE" || true
rm "$PATCH_FILE.bak"

# 3. Patch the sidebar recent-thread provider filter (single occurrence)
SIDEBAR_FILE=$(grep -RIl 'listRecentThreads' extracted/webview/assets/app-server-manager-signals-*.js | head -n1)
node - "$SIDEBAR_FILE" <<'JS'
const fs = require("node:fs");
const path = process.argv[1];
const text = fs.readFileSync(path, "utf-8");
const old = "listRecentThreads({cursor:e,limit:t}){return this.params.requestClient.sendRequest(`thread/list`,{limit:t,cursor:e,sortKey:this.recentConversationSortKey,modelProviders:null,archived:!1,sourceKinds:ke})}";
const next = "listRecentThreads({cursor:e,limit:t}){return this.params.requestClient.sendRequest(`thread/list`,{limit:t,cursor:e,sortKey:this.recentConversationSortKey,modelProviders:[],archived:!1,sourceKinds:ke})}";
if (text.split(old).length - 1 !== 1) throw new Error("expected one sidebar provider filter occurrence");
fs.writeFileSync(path, text.replace(old, next));
JS

# 4. Repack
npx --yes @electron/asar pack extracted app.asar.new
sudo cp app.asar.new "$APP/Contents/Resources/app.asar"

仅做到这一步会让 Codex 下次启动时以 EXC_BREAKPOINT 崩溃。Electron 在 Info.plist 中的 ElectronAsarIntegrity 字段是 ASAR 归档 JSON 头(而非整 个文件)的 SHA-256。重新计算并重新签名:

# 5. Compute new header hash
HEADER_HASH=$(node - "$APP/Contents/Resources/app.asar" <<'JS'
const fs = require("node:fs");
const crypto = require("node:crypto");
const fd = fs.openSync(process.argv[1], "r");
const head = Buffer.alloc(16);
fs.readSync(fd, head, 0, 16, 0);
const jsonSize = head.readUInt32LE(12);
const json = Buffer.alloc(jsonSize);
fs.readSync(fd, json, 0, jsonSize, 16);
fs.closeSync(fd);
console.log(crypto.createHash("sha256").update(json).digest("hex"));
JS
)
echo "new header hash: $HEADER_HASH"

# 6. Patch Info.plist (replaces the hash for Resources/app.asar)
sudo /usr/libexec/PlistBuddy -c \
  "Set :ElectronAsarIntegrity:Resources/app.asar:hash $HEADER_HASH" \
  "$APP/Contents/Info.plist"

# 7. Ad-hoc re-sign
sudo codesign --force --deep --sign - "$APP"

# 8. Launch
open "$APP"

回滚方法:sudo rm -rf "$APP" && sudo mv "$APP.unpatched-…" "$APP"。

CLI 也提供修补/恢复 app.asar 及对应 ASAR 完整性元数据的辅助命令:

codex-forge-cli patch-app
codex-forge-cli restore-app

如果 patch-app 之后 Codex 仍然崩溃,用 codex-forge-cli restore-app 恢复,并对照 已安装的 Desktop 构建重新检查手工补丁的定位串。


ChatGPT/Codex 透传

如果 ~/.codex/auth.json 存在且包含 tokens.access_token,forge 会暴露一个合 成的 gpt-5.5 目录条目,直接代理到:

https://chatgpt.com/backend-api/codex/responses

该条目仅在令牌存在时才会出现在 /health、/v1/models、codex-forge-cli list 和生成的 ~/.codex-forge/cli/model_catalog.custom.json 中。一旦你 codex logout 或文件缺 失,该 slug 就不再出现 —— 选择器因此永远不会显示一个首次使用就会 401 的选 项。运行 codex login 获取新令牌后,下一次 codex-forge-cli generate 会自动恢复 该条目。

透传保持 Codex 原生的 /v1/responses 载荷不变,把模型改为 gpt-5.5,并以 Authorization: Bearer <access_token> 发送你的 Codex 访问令牌,同时在存在时 附上 auth.json 中的 ChatGPT 账户 id。它完全绕过配置的 BYOK 路由,使用你的 ChatGPT 订阅额度。

codex-forge-cli generate 之后它就已经在 ~/.codex-forge/cli/model_catalog.custom.json 中。在选择器里选择 GPT-5.5,或运行:

codex-forge-cli model use gpt-5.5

旧的本地配置或笔记可能使用 openai-gpt-5-5;服务器接受该前缀作为别名并路由 到同一透传。


路由工作原理

Codex Desktop ── /v1/responses ──▶ codex-forge (127.0.0.1:58767)
                                     │
                                     ├── slug "gpt-5.5"
                                     │       └─▶ chatgpt.com/backend-api/codex/responses
                                     │           (Authorization: Bearer <auth.json access_token>)
                                     │
                                     ├── provider "openai" / "generic-…"
                                     │       └─▶ baseUrl/chat/completions
                                     │           (Authorization: Bearer apiKey)
                                     │
                                     └── provider "anthropic"
                                             └─▶ baseUrl/messages
                                                 (x-api-key: apiKey, anthropic-version: …)

forge 把 Codex 的 Responses-API 请求翻译成上游的形状(chat completions 或 Anthropic Messages),并把流式回复翻译回来。来自 Anthropic 形态上游(Claude、 DeepSeek、GLM 等)的 extended-thinking 块通过 reasoning.encrypted_content 条 目往返。


Auto Router(智能路由)

可选地增加一个额外的选择器条目 —— Auto (smart routing)(slug codex-auto)—— 它会按任务选择合适的模型:简单轮次走便宜模型,困难轮次升 级到最强模型。它完全基于你已配置的模型运行。

每个新任务开始时,forge 让你指定的便宜分类器模型给每个候选打分 0.0–1.0 (一次搞定该任务的可能性),分类器会读取每个候选的简短能力卡片。然后路由 到分数超过 threshold(默认 0.7)的最便宜候选,为该任务的工具调用往返 缓存该决策,并在任何错误时安全回退。分类器永远看不到价格,因此不会偏向昂贵模 型。

在 ~/.codex-forge/server/models.toml 中添加 [router] 段即可开启:

[router]
enabled = true
slug = "codex-auto"
classifier = "minimax-m3"        # slug of a cheap configured model
threshold = 0.7
default = "minimax-m3"
cache = true

[[router.candidates]]
slug = "minimax-m3"
cost = 0.3
supports_images = false
card = "Cheap, fast. Single-file edits, codegen, simple refactors."

[[router.candidates]]
slug = "opus"
cost = 5.0
supports_images = true
card = "Frontier. Big multi-file refactors, hard debugging, images."

不需要 key 和网络即可端到端验证:

node examples/auto_router_demo.mjs

它会启动一个 mock 多后端服务器、以开启路由器的真实 forge 运行,并演示 简单→便宜、中等→中档、困难→强力、图像→支持图像、以及重复任务命中缓存。完整 配置、环境开关(CODEX_FORGE_ROUTER_LOG、CODEX_FORGE_DISABLE_ROUTER …)和故 障行为见 docs/AUTO_ROUTER.md。


工具调用与 agent 循环

Codex 期望 Responses-API 输出条目。大多数 BYOK 上游说 OpenAI chat completions 或 Anthropic Messages。forge 弥合这一差距:

| Codex/Responses 条目 | OpenAI 形态上游 | Anthropic 上游 | |---|---|---| | tools: [{type: "function", ...}] | tools: [{type: "function", function: ...}] | tools: [{name, description, input_schema}] | | function_call 输出条目 | Chat tool_calls[] | tool_use 内容块 | | function_call_output 输入条目 | Chat role: "tool" 消息 | tool_result 用户内容块 | | 流式参数增量 | response.function_call_arguments.delta | response.function_call_arguments.delta | | 并行调用 | 支持处通过 parallel_tool_calls 保留 | 多个 tool_use 块 |

正是这部分让 forge 对真实 Codex 运行有用,而不仅仅是文本聊天。模型可以让 Codex 运行工具,Codex 把工具输出经 forge 送回,上游模型继续同一循环。

原生 Responses 专属工具现在有 BYOK 回退:

| Responses 工具 | Chat/Anthropic 回退 | |---|---| | computer_use / computer_use_preview | computer_use 函数,参数 {action, x, y, text, ...} | | web_search / web_search_preview | web_search 函数,参数 {query, ...} | | apply_patch | apply_patch 函数,参数 {patch, ...} | | local_shell / shell | local_shell 函数,参数 {command, ...} | | Codex MCP 函数 | 作为普通函数工具透传 |

即使上游 API 是 chat-completions 或 Anthropic Messages 而非原生 Responses,BYOK 模型也能留在 Codex agent 循环里。ChatGPT 透传仍是第一方托管工具条目形状的最高 保真路径,但 BYOK 路由不再丢弃这些工具。支持视觉的 BYOK provider 会保留视觉反 馈:Responses input_image、computer_call_output 截图和视觉 function_call_output 载荷会变成 OpenAI chat image_url 部分或 Anthropic image 块,而不是被压平成文本。

已知边界情况:

  • BYOK 原生工具回退依赖 Codex 客户端/运行时识别并执行回退函数调用。forge 翻译 工具 schema 并往返工具输出;它本身不执行 computer、shell、patch 或 MCP 动 作。
  • 一些 OpenAI 兼容 provider 宣称支持工具调用但流式输出格式错误的 JSON 参数。 forge 保留增量;provider 仍须在调用结束时给出合法 JSON。
  • 如果 provider 忽略 parallel_tool_calls,Codex 可能仍一次只请求一个工具。 这是上游行为,不是目录问题。

web_search 服务端拦截

Codex Desktop 无法为 BYOK 模型执行 web_search 工具。当模型在流式响应中只产出 web_search 调用而无文本内容时,Codex Desktop 会标记调用为 "completed" 但无结果, 导致模型反复调用 web_search → 空白响应无限循环。

forge 在流式和非流式路径上均拦截 web_search_call,在服务端执行搜索(DuckDuckGo), 将结果作为 tool 消息追加到 follow-up 请求中,让模型基于搜索结果合成回答—— 所有操作在同一个 SSE 流内完成,对 Codex Desktop 透明。主要特性:

  • 递归拦截:若 follow-up 中模型再次调用 web_search,自动执行第二/三轮搜索(上限 3 轮)。
  • DSML 过滤:DeepSeek 在 web_search 被剥离后可能以 <||DSML||tool_calls> 文本 形式发出工具调用标记;filterDsml() 跨 chunk 缓冲并过滤这些标记。
  • 完整输出保留:各轮 reasoning / web_search_call / message 通过 completedItems 在 response.completed 事件中一并返回。

会话压缩(Compaction)

Codex 可通过 POST /v1/responses/compact 压缩长会话。

| 路由 | 行为 | |---|---| | ChatGPT 透传(gpt-5.5 / openai-gpt-5-5*) | 转发到 ChatGPT 原生的 /backend-api/codex/responses/compact 端点,并把返回的模型元数据改写回请求的 forge slug。 | | BYOK OpenAI/chat-completions provider | 通过 /chat/completions 发送非流式摘要请求,然后返回 Responses 形状的压缩窗口,其 output 可用作下一次 input。 | | BYOK Anthropic provider | 通过 /messages 发送非流式压缩请求,然后返回相同的 Responses 形状压缩窗口。 |

BYOK 路径在转发前有意剥离 stream、service_tier 等对 provider 不友好的字 段。它保留实用的 Codex 行为 —— 更小的下一上下文窗口 —— 而不假装第三方 chat API 能发出 OpenAI 那种不透明的加密压缩条目。


Computer use、shell 命令、图像与 MCP

生成的目录声明了 Codex 作为 agent 运行所需的能力:

| 目录字段 | 取值 | |---|---| | shell_type | shell_command | | apply_patch_tool_type | freeform | | web_search_tool_type | text_and_image | | supports_parallel_tool_calls | true | | input_modalities | text,image,除非 noImageSupport: true | | supports_image_detail_original | noImageSupport: true 时禁用 |

实际含义:

  • Shell/文件操作仍由 Codex Desktop/CLI 执行。forge 只翻译模型请求和响应流。
  • 图像/截图可以传给接受图像的 provider。Responses input_image 条目、 computer_call_output 截图和视觉工具输出会保留为 OpenAI chat image_url 部分或 Anthropic image 块。对纯文本上游设置 noImageSupport: true,避免 Codex 发送它们无法解析的图像内容。
  • Computer-use/原生托管工具在 ChatGPT 透传路径上使用原生 Responses 条目类 型。BYOK chat/Anthropic 路由获得确定性的函数工具回退(computer_use、 web_search、apply_patch、local_shell),从而留在同一 Codex 工具循环中。

Codex Desktop 会向每个模型转发三个通用 MCP 工具:

  • list_mcp_resources
  • list_mcp_resource_templates
  • read_mcp_resource

它不会把各个 MCP server 的工具压平进函数列表。这是 Codex 客户端行为,不 是 forge 的限制。forge 路由的模型与内置 OpenAI 模型收到同样的 MCP 工具。模型应 调用 list_mcp_resources 来发现可用内容。


提示词捕获与请求拦截

有两个实用的拦截层:

1. 内置请求日志

每个 /v1/responses 请求的入站、转发和响应都会记录到 ~/.codex-forge/server/logs/ 下的 分类日志文件中:

| 文件 | 内容 | |------|------| | requests.log | 入站请求(模型、工具列表、输入摘要)、转发(slug、URL、prompt 预览)、响应(状态码、响应预览);上游错误也写入此文件 | | errors.log | 上游错误与异常 | | lifecycle.log | 服务启动/停止等生命周期事件 |

tail -f ~/.codex-forge/server/logs/requests.log

日志使用本地时间 + 毫秒精度时间戳(YYYY-MM-DD HH:mm:ss.SSS),API key 等敏感字段 自动脱敏。流式响应采用累积预览模式,捕获完整响应摘要而非仅首个 chunk。

2. forge 前面的本地提示词捕获代理

需要更深控制时,在 codex-forge 前面放一个小型本地代理,并让 Codex 指向该代 理。该层可以在完整 Responses 请求到达 forge 之前检查它,然后转发到 http://127.0.0.1:58767/v1/responses。

常见用途:

  • 注入稳定的 system/developer 前言;
  • 在重复样板文本烧掉 token 之前剥离它;
  • 把 XML 风格的 <invoke ...> 草稿等伪工具文本修复为结构化工具调用,再让 Codex 看到;
  • 把部分提示词路由到 ChatGPT 透传、其余路由到 BYOK 模型;
  • 在日志中对大文件块做脱敏或哈希。

最小 Node.js 转发器形态(仅标准库):

import http from "node:http";

const UPSTREAM = "http://127.0.0.1:58767";

function catchPrompt(body) {
  // Keep this deterministic. Codex retries are much easier to debug when the
  // same input produces the same transformed payload.
  return body;
}

http.createServer(async (req, res) => {
  if (req.method === "POST" && req.url === "/v1/responses") {
    let raw = "";
    for await (const chunk of req) raw += chunk;
    const body = catchPrompt(JSON.parse(raw)); // mutate or record the payload
    const upstream = await fetch(`${UPSTREAM}/v1/responses`, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(body),
    });
    res.writeHead(upstream.status, { "content-type": upstream.headers.get("content-type") || "application/json" });
    res.end(Buffer.from(await upstream.arrayBuffer()));
  } else {
    res.writeHead(404).end();
  }
}).listen(8766, "127.0.0.1");

然后启动 Codex 时把 forge provider URL 设为 http://127.0.0.1:8766/v1 而不是 58767。除非你想让所有 BYOK 路由共享同一变更策略,否则把提示词捕获放在 src/translate.mjs 之外。


成本与速度基准测试

正确的基准是真实的 Codex 任务,而不是合成的 hello-world 补全。用同一仓库、同 一提示词、同一模型和同一工具预算对比不同路由。

建议的快速协议:

  1. 选一个用到工具的真实任务,例如"找到 bug、修改文件、运行聚焦测试"。
  2. 分别通过你的基线 Codex 路由和 gpt-5.5 透传(或你的 BYOK 模型)各跑一 次。
  3. 记录墙钟时间、请求数、输入 token、输出 token、工具调用次数和最终测试结 果。
  4. 只对比端到端成功的运行。

实用的 shell 计时包装:

/usr/bin/time -f 'wall=%E cpu=%P max_rss_kb=%M' codex-forge-cli codex -- "your task here"

包装器接受并剥离 -- 分隔符。它是可选的,但能防止以 - 开头的任务提示词被 解析为包装器标志。

一份好的报告形如:

Oracle: same repo commit, same prompt, same focused test command
Baseline: 12 requests, 210k input tokens, 19k output tokens, 18m42s, test passed
Forge:     8 requests,  31k input tokens, 11k output tokens,  2m35s, test passed
Result:   6.8x fewer billed input tokens, 7.2x faster wall time

具体倍数取决于模型、提示词捕获策略、仓库大小、网络路径和 agent 调用工具的频 率。


命令

codex-forge-cli generate          通过 API 触发目录和配置生成
codex-forge-cli list              查看可用模型列表
codex-forge-cli enable            写入 Codex 配置(需要服务已运行)
codex-forge-cli show              查看工具端状态
codex-forge-cli doctor            只读诊断报告
codex-forge-cli disable           移除托管配置块并恢复原配置
codex-forge-cli model list        列出可用模型
codex-forge-cli model current     查看当前模型
codex-forge-cli model use <slug>  切换默认模型
codex-forge-cli config show       查看服务器连接配置
codex-forge-cli config set <k> <v> 修改连接配置 (host, port, token)
codex-forge-cli codex -- <args>   一次性 CLI 任务
codex-forge-cli app [path]        启动 Codex Desktop
codex-forge-cli patch-app         修补 macOS Codex Desktop 选择器
codex-forge-cli restore-app       恢复 macOS app.asar

全局标志:

  • --settings <path>:仅用于本地 doctor 诊断,不会传给远程 server。
  • --host <host>:工具端连接地址(默认 127.0.0.1)。
  • --port <port>:服务端端口(默认 58767)。
  • --token <token>:当 server 启用 bearer token 时使用的连接令牌。

patch-app 和 restore-app 始终针对 /Applications/Codex.app,不使用 --settings,在 Windows/Linux 上会以明确错误退出。

初始配置与默认模型选择

enable 和 app 会把 codex-forge 的 provider 配置写入 ~/.codex/config.toml。 写入时需要决定当前激活哪个模型,逻辑如下:

  1. 显式传入的 model use <slug> / -m <slug>。
  2. 本地 ~/.codex/config.toml managed block 中已有的模型。
  3. server 返回的第一个可用模型。

server 不返回“客户端 active model”;这个状态只属于 CLI 所在主机。


模型切换

模型切换由 CLI 完成,server 不写 ~/.codex/config.toml,也不重启 Codex Desktop:

codex-forge-cli model list
codex-forge-cli model current
codex-forge-cli model use <slug>

旧的 GET /picker 已移除;POST /api/switch 返回 410 Gone,响应中提示使用 codex-forge-cli model use <slug>。


安全与隐私

  • forge 默认绑定 0.0.0.0,可用 --host/--port 或 ~/.codex-forge/cli/cli.json 修改。
  • server 设置 CODEX_FORGE_TOKEN 后,除 / 和 /health 外的 API 都要求 Authorization: Bearer <token>。
  • CLI 可用 config set token <token> 或 --token <token> 保存/传入连接令牌。
  • 远程直连模式会把该 token 写入 Codex provider 的 bearer 配置;如果不希望把 token 写入 Codex 配置,请使用 TLS 反向代理承担认证。
  • API key 留在你的设置文件中;生成的目录不包含它们。
  • 请求日志自动脱敏 API key 等敏感字段;日志级别可通过 CODEX_FORGE_LOG_LEVEL 环境变量调整。
  • 运行时目录默认是 ~/.codex-forge/;可用 CODEX_FORGE_RUNTIME_DIR 指向别处 (支持绝对路径、相对路径或 ~/…)。用于 CI/容器把运行时状态放在真实 home 之外;测试也用它隔离,避免污染真实目录。
  • ChatGPT 透传在请求时读取 ~/.codex/auth.json,且只把访问令牌转发给 ChatGPT 的 Codex 端点。
  • 如果你在 forge 前面放了提示词捕获代理,该代理控制自己记录什么。请在那里对 大型/私有提示词正文做脱敏或哈希。

已知限制

  • Codex 内部和模型选择器打包文件会变。ASAR 补丁天然对版本敏感。
  • ChatGPT 透传端点是当前 Codex 构建使用的端点;未来的 Codex 版本可能移动或改 变其形状。
  • BYOK provider 的工具调用质量参差不齐。forge 翻译形状;它无法让上游模型可靠 地发出合法的工具调用 JSON。
  • 托管的 Responses 专属工具在 ChatGPT 透传路径上保真度最高。BYOK 路由获得普 通函数工具翻译。
  • bin/ 下的 POSIX shell 脚本在原生 Windows shell 中不可用,请改用 node src/run.mjs ...。

故障排查

Forge 无法启动

codex-forge-cli doctor
codex-forge-cli show
tail -n 80 ~/.codex-forge/server/server.log

codex-forge-cli doctor 输出按分节组织的只读诊断报告。报告混合了两类检查,读的 时候需要区分:

  • 本地文件检查:Node.js / Codex CLI 版本、Local settings(本机上的 ~/.codex-forge/server/models.toml)、Codex 配置、代理绕过 —— 它们只描述 当前这台主机。
  • HTTP 检查:守护进程健康、透传可用性等 —— 它们是对配置的 host 发起的 HTTP 调用,描述的是远端或本地 server,而不是本机文件。

当 client 主机指向远程 server 时,本机没有 models.toml 是正常的:server 的 server/models.toml 位于 server 主机,因此 Local settings(该分节在跨主机时 标题为 Local settings (this host only))会把缺失的本地文件报告为 INFO,只有 同机部署时才报告 WARN。

该命令从不写配置、不启动/停止守护进程、不调用模型 provider,也不打印 API key/令牌。只有检测到硬性 FAIL 时才以 1 退出;警告意在作为本地配置提示。

常见原因:

  • Node.js 版本低于 22。
  • 端口 58767 已被占用。换端口启动:
codex-forge-server start --port 8766
codex-forge-cli --port 8766 enable

~/.codex-forge/server/models.toml 缺失

只用 ChatGPT 透传时这没问题,前提是 server 主机 ~/.codex/auth.json 有有效的 tokens.access_token。此时 CLI 生成的目录只包含 gpt-5.5。如果 server 既没有 BYOK 模型也没有有效登录,codex-forge-cli list 会以非零退出:

codex-forge-server start --settings /path/to/my-models.toml

codex-forge-cli list 以 "No models available" 退出 1

server 既没有在 ~/.codex-forge/server/models.toml 配置模型, 也没有有效的 Codex 登录。二选一:

codex login                       # populate ~/.codex/auth.json
# or, on the server host
codex-forge-server start --settings /path/to/my-models.toml

Codex 只显示 default

运行:

codex-forge-cli generate
codex-forge-cli model list

如果目录里有你的模型但 Desktop 仍隐藏它们,使用 macOS 选择器补丁。在 Windows Store/MSIX Desktop 上,同一允许列表可能把激活模型改回 gpt-5.5;BYOK 路由请 用 codex-forge-cli codex -- ... / Codex CLI,或使用能在不改写配置的情况下读取自 定义目录的非 MSIX/Desktop 构建。

Windows 代理把回环流量引离了 forge

如果 forge 健康但 codex.exe 返回代理/502 错误,可能是系统代理在拦截 http://127.0.0.1:58767。启动 Codex 前设置大小写两套绕过变量:

$env:NO_PROXY = "127.0.0.1,localhost,::1"
$env:no_proxy = "127.0.0.1,localhost,::1"

codex-forge-cli app ... 和 codex-forge-cli codex -- ... 会为子进程自动设置这些条 目。

模型出现但请求 404

所选 slug 不在当前生成的目录中。编辑 server 主机上的 ~/.codex-forge/server/models.toml(或 --settings 指定的文件),然后重新生成:

codex-forge-cli generate
codex-forge-cli model list
codex-forge-cli model use <slug>

上游返回 401/403

模型设置文件里的 API key 错误、过期或缺少 provider 特定的头。ChatGPT 透传 请刷新 Codex 登录,使 ~/.codex/auth.json 包含有效的 tokens.access_token。

工具调用变成文本

先用 ChatGPT 透传路径确认 Codex 本身在发送工具。如果透传正常但某 BYOK 路由不 行,上游可能缺少原生工具调用支持或发出格式错误的流式参数。查看 ~/.codex-forge/server/server.log 中请求的模型和工具数量。

纯文本模型上图像失败

在设置文件中为该模型设置 "noImageSupport": true 并重新生成目录。

流式输出挂起

检查上游在 Codex 之外是否能正常流式输出。然后重启本地守护进程:

codex-forge-server restart
tail -f ~/.codex-forge/server/server.log

服务器使用较长的读超时,因为真实的编码 agent 轮次可能流式输出很久;静默挂起 通常是上游/网络/provider 行为。

打补丁后 macOS 应用崩溃

你重新打包了 app.asar 但没更新 ElectronAsarIntegrity 并重新签名,或者补丁 命中了错误的 JavaScript 打包文件。恢复后重试:

codex-forge-cli restore-app
codex-forge-cli patch-app

重置生成的 forge 状态

codex-forge-server stop
# 按角色清理:只删本机对应的子目录即可
rm -rf ~/.codex-forge/server    # 仅清理本机作为 server 主机时的服务端状态
rm -rf ~/.codex-forge/cli       # 仅清理本机作为 client 主机时的工具端状态
# 如需完全清除运行时状态,也可以手动删除整个 ~/.codex-forge/;
# 这会同时移除 server 与 cli 两侧,跨主机部署时需在各自主机上分别执行
codex-forge-cli generate
codex-forge-server start

文件结构

src/                     Node.js ESM source (server + cli + translation)
dist/                    built publishable tree (output of scripts/build.mjs)
bin/codex-forge-cli     main entrypoint
bin/codex-forge-server   server daemon manager
~/.codex-forge/server/   server host runtime: models.toml, pid, logs, debug (gitignored)
~/.codex-forge/cli/      client host runtime: cli.json, model catalog, backups (gitignored)
tests-node/              node:test suite

配置行为:

  • codex-forge-cli generate、list、show、doctor、codex-forge-cli codex -- ... 不会持久修改 ~/.codex/config.toml。
  • codex-forge-cli enable、codex-forge-cli app 和 codex-forge-cli model use <slug> 会 向 ~/.codex/config.toml 写入托管块。如果已有的顶层 Codex 模型键被顶替, 托管块会记录它们,使 disable 能恢复这些键而不回滚无关的配置修改。
  • codex-forge-cli disable 移除托管块、在存在时恢复被顶替的顶层模型键。

许可证

MIT —— 见 LICENSE。

Codex Desktop 是 OpenAI 的商标。本项目与其无关联。