一个轻量级的 Codex Web 界面,用来在浏览器中直接运行和管理 Codex App 原生任务与会话。
本项目完全由 AI 制作,未经过正式安全审计。部署、公开访问或处理敏感数据前,请自行检查代码、依赖、配置、鉴权逻辑和运行环境安全。
- 在浏览器里创建、切换和继续 Codex App 原生会话
- 通过持久
codex app-server实现 Web 与 Codex App 双向同步 - 只显示 Codex App 中未归档的普通用户会话,不显示自动化任务
- 最近会话按工作目录分组,显示项目名与完整路径
- 支持会话改名、归档和历史记录管理
- 支持从历史用户消息创建原生会话分支,恢复原消息后修改并重新发送
- 支持流式显示助手回复与思考摘要;历史思考和工具调用默认折叠
- 每轮只保留最新一次工具调用,助手输出支持安全 Markdown
- 支持取消任务以及命令、文件、权限、用户输入和 MCP 请求确认
- 浏览器断开后,已启动的任务会继续在服务端运行
- 手机切换应用、页面恢复或 SSE 重连时会保留流式消息,并在完整历史落盘后安全同步
- 支持上传图片、PDF、文本和代码附件
- 内置 Image Prompt 案例与模板库,支持搜索、预览并发送到生图工作台
- 内嵌 GPT Image Playground,支持生成、编辑、参考图、遮罩和浏览器本地历史
- 提供登录保护的生图同源代理,可绕过第三方 Image API 的浏览器 CORS 限制
- 支持管理模型服务商和默认模型
- 支持为已有服务商重新获取最新模型列表
- 支持选择并保存模型思考档位:默认、low、medium、high、xhigh
- 支持删除服务商,且会防止删除最后一个服务商
- 支持界面外观设置和自定义聊天背景
- 内置光粒背景特效与鼠标追随光线,自动适配明暗主题与背景
- 提供健康检查接口:
/api/health
界面内置两层轻量 Canvas 特效,由根目录 effects.js 实现,不依赖任何第三方库:
- 光粒特效:屏幕上漂浮的发光粒子,缓慢漂移并呼吸闪烁,颜色取自当前主题的
--primary、--info、--thinking - 鼠标追随光线:指针移动时产生渐隐的发光拖尾与柔和光晕,光粒会被光标轻微吸引
行为细节:
- 自动跟随明暗主题与 Dream Skin 配色;浅色主题使用普通混合并降低亮度
- 使用自定义背景或 Dream Skin 壁纸时,特效自动降低透明度,避免干扰背景
- 尊重系统
prefers-reduced-motion,开启时只绘制静态画面 - 标签页隐藏时暂停渲染,不占用 CPU
- 画布
pointer-events: none,不会拦截点击与滚动
调整效果强弱时,直接修改根目录 effects.js 中的参数即可:
- 光粒密度:
spawnParticles()中的密度系数18000与数量上限110 - 光粒大小与亮度:粒子
size、alpha随机范围 - 拖尾长短与亮度:
TRAIL_MS、MAX_TRAIL_POINTS以及绘制时的透明度系数 - 光标光晕亮度:
drawCursorGlow()中的透明度数值
修改后重启服务并强制刷新页面(Ctrl+Shift+R)即可生效。
- Node.js 22.5 或更高版本(原生会话索引依赖
node:sqlite) - npm
- 运行主机已安装并配置可用的 Codex CLI;历史分支功能需要 0.144.4 或更高版本
npm install
npm run setupnpm run setup 会生成仅监听 127.0.0.1 的 .env,自动发现 Codex CLI,并创建随机登录密码和会话密钥。也可以跳过该命令,手动复制并编辑 .env.example。
适合把 Codex Web 作为独立服务跑在 Docker 里。容器内已安装 Node.js 与 @openai/codex CLI;需要把宿主机的 Codex 配置/会话目录挂载到 /data/codex,才能读取原生会话。
注意:Codex Desktop IPC / 本机 App 窗口联动在容器里通常不可用。容器模式默认关闭
CODEX_DESKTOP_IPC_ENABLED,并通过容器内codex app-server工作。
cp .env.docker.example .env
# 编辑 .env:至少设置 CODEX_WEB_PASSWORD 和 SESSION_SECRET如果本机已有 Codex 数据,可把 CODEX_HOME_HOST 指到真实目录,例如:
CODEX_HOME_HOST=$HOME/.codexdocker compose up -d --build
docker compose ps
curl -fsS http://127.0.0.1:36354/api/health浏览器打开 http://127.0.0.1:36354,用 .env 中的密码登录。
docker compose logs -f codex-web
docker compose restart codex-web
docker compose down默认镜像名:ikirito9/codex-web:latest
docker build -t ikirito9/codex-web:latest .
docker push ikirito9/codex-web:latest
# 或:
docker compose build
docker compose push多架构示例:
docker buildx build --platform linux/amd64,linux/arm64 \
-t ikirito9/codex-web:latest --push .| 容器路径 | 默认宿主机路径 | 内容 |
|---|---|---|
/data/codex |
./data/codex |
Codex 配置、session index、原生会话 |
/data/runtime |
./data/runtime |
Web 运行时状态、上传、队列 |
/workspaces |
./data/workspaces |
默认工作目录 |
真实 .env、data/ 与密钥不要提交到 Git。
项目会从项目目录的 .env 和 CODEX_HOME 下的 Codex 配置文件读取运行配置。
手动配置时,复制示例文件后再填写当前主机的配置:
cp .env.example .env.env.example 只包含脱敏占位符,可以提交到仓库;真实 .env 不要提交。
如果是新设备首次运行,还需要准备 Codex 配置:
${CODEX_HOME:-$HOME/.codex}/.env:保存服务商 API Key,可参考codex.env.example${CODEX_HOME:-$HOME/.codex}/config.toml:保存服务商和模型配置,可参考codex.config.example.toml
默认以只读方式使用主机 Codex 配置。只有显式设置 CODEX_CONFIG_WRITABLE=true 后,Web 中的服务商管理和默认设置写入功能才会显示。
主要环境变量:
| 变量 | 说明 |
|---|---|
CODEX_WEB_PASSWORD |
Web 登录密码,必填 |
SESSION_SECRET |
登录会话签名密钥,建议设置为稳定的随机字符串 |
SESSION_TTL_HOURS |
登录有效期,默认 168 小时 |
HOMEPAGE_API_TOKEN |
Homepage 统计接口访问令牌;未设置时接口禁用 |
HOMEPAGE_MODEL_CACHE_SECONDS |
Homepage 模型数量缓存秒数,默认 60 |
CPA_QUOTA_BASE_URL |
CPA Management 地址;与 CPA_QUOTA_API_KEY 同时设置后启用 CPA Codex 额度 |
CPA_QUOTA_API_KEY |
CPA Management Key,仅保存在服务端本地 .env |
SUB2API_BASE_URL |
Sub2API 地址;旧的单 CPA 配置仍可通过 SUB_QUOTA_PROVIDER=cpa-codex 兼容读取 |
SUB2API_API_KEY |
Sub2API API Key;旧的单 CPA Management Key 仍兼容读取 |
SUB2API_ADMIN_API_KEY |
可选的 Sub2API 管理 API Key;仅在服务端用于补充 Codex 账号 5 小时/7 天额度 |
GROK2API_BASE_URL |
Grok2API 管理面板地址;与 GROK2API_ADMIN_PASSWORD 同时设置后启用 Grok2API 额度 |
GROK2API_ADMIN_PASSWORD |
Grok2API 管理员密码(或 username:password),仅保存在服务端本地 .env |
DEEPSEEK_BASE_URL |
DeepSeek 官方 API 地址,默认 https://api.deepseek.com |
DEEPSEEK_API_KEY |
DeepSeek 官方 API Key;设置后启用 DeepSeek 官方余额监控,仅保存在服务端本地 .env |
SUB_QUOTA_TIMEOUT_MS |
额度请求超时,默认 10000 毫秒 |
SUB_QUOTA_CACHE_SECONDS |
额度结果缓存时间,默认 30 秒 |
IMAGE_PROMPT_AUTO_SYNC |
启动时及定时检查 awesome-gpt-image-2 更新,默认开启 |
IMAGE_PROMPT_SYNC_INTERVAL_MINUTES |
提示词库自动检查间隔,默认 360 分钟 |
IMAGE_PROMPT_SYNC_TIMEOUT_MS |
单次 GitHub 请求超时,默认 20000 毫秒 |
PLAYGROUND_UPDATE_ENABLED |
是否显示并启用生图工作台一键更新,默认开启 |
IMAGE_PROMPT_GITHUB_TOKEN |
可选 GitHub Token,仅用于提高 API 速率限制 |
PLAYGROUND_PROXY_TIMEOUT_MS |
生图工作台同源代理请求超时,默认 690000 毫秒 |
CODEX_WEB_SHUTDOWN_GRACE_MS |
重启时等待进行中的代理请求完成,默认 120000 毫秒 |
PLAYGROUND_PROXY_ALLOWED_ORIGINS |
额外允许代理访问的 API Origin,多个值使用英文逗号分隔 |
HOST |
监听地址,默认 127.0.0.1 |
PORT |
固定监听端口,示例为 36354 |
CODEX_BIN |
Codex CLI 路径;初始化脚本会优先发现 ChatGPT/Codex App 内置版本 |
CODEX_HOME |
Codex 配置、索引和原生会话目录,默认 $HOME/.codex |
CODEX_WEB_LOCAL_IMAGE_ROOTS |
可选的绝对图片根目录白名单,多个目录用英文逗号分隔;用于显示助手消息中来自其他项目的本地图片 |
APP_SERVER_REQUEST_TIMEOUT_MS |
codex app-server 单次协议请求超时,默认 30000 毫秒 |
CODEX_DESKTOP_IPC_ENABLED |
macOS/Windows 默认开启;续聊优先交给当前打开任务的 Codex App 窗口 |
CODEX_DESKTOP_IPC_TIMEOUT_MS |
Codex App 桌面 IPC 请求超时,默认 20000 毫秒 |
CODEX_DESKTOP_IPC_SOCKET |
可选的桌面 IPC socket/pipe 覆盖路径,通常留空自动发现 |
NATIVE_SESSION_POLL_MS |
原生会话文件监听的轮询兜底间隔 |
DEFAULT_PROVIDER |
新会话默认服务商 |
DEFAULT_MODEL |
新会话默认模型 |
DEFAULT_CWD |
新会话默认工作目录 |
DEFAULT_SANDBOX |
Codex 默认沙箱模式 |
DEFAULT_APPROVAL |
Codex 默认审批模式 |
左侧额度入口可同时查询本地 CLIProxyAPI(CPA)Codex 账号额度、Sub2API 额度、Grok2API 账号池与 DeepSeek 官方余额。悬停额度图标显示各渠道只读额度卡,点击图标可分别填写各组 URL 与 Key。配置会先保存,额度检测独立刷新,连接或凭证错误不会阻止配置落盘。CPA 通过 /v0/management/auth-files 找到 Codex 凭证,再经 /v0/management/api-call 请求 chatgpt.com/backend-api/wham/usage;Sub2API 通过 /v1/usage 读取订阅、余额与 API Key 限速窗口;Grok2API 通过管理面板汇总账号池,并展示正常账号、风控、需关注、异常、恢复中、冷却、禁用等账号状态数量。可选设置 SUB2API_ADMIN_API_KEY 后,服务端还会读取 /api/v1/admin/accounts 中缓存的 Codex 提供商账号 5 小时/7 天使用百分比;管理 Key 不会发送到浏览器。
DeepSeek 官方额度:余额通过官方 GET https://api.deepseek.com/user/balance 实时查询;官方 API 未开放累计消费/用量查询接口,因此累计 Token 由本服务根据每次实际 API 调用返回的 usage 本地累计,仅供参考。可在额度设置的“本地累计校准”中填写官网当前显示的累计 Token 与累计请求,后续调用会从该基准继续累加。统计文件保存在 runtime/deepseek-usage.json。
CPA_QUOTA_BASE_URL=http://127.0.0.1:8327
CPA_QUOTA_API_KEY=<replace-with-cpa-management-key>
SUB2API_BASE_URL=https://sub.example.com
SUB2API_API_KEY=<replace-with-sub2api-key>
SUB2API_ADMIN_API_KEY=<optional-sub2api-admin-key>
GROK2API_BASE_URL=http://127.0.0.1:8100
GROK2API_ADMIN_PASSWORD=<optional-grok2api-admin-password>
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_API_KEY=<replace-with-deepseek-api-key>
SUB_QUOTA_PROVIDER=multi各组 URL 与 Key 均可在额度设置弹窗中保存,环境变量仍可用于首次或手工配置。真实 Key 只应写入已忽略的本地 .env,不要写入 .env.example、README、提交记录或浏览器端代码。点击设置时 Key 输入框不会回显现有值,留空不会替换对应来源的当前 Key。只配置一路时仍会正常显示;多路均配置后会在同一个额度弹层中依次显示。
浏览器直接请求第三方 Image API 时,可能因上游拒绝 CORS 预检而显示 Failed to fetch。Codex Web 内置登录保护的 /api-proxy/* 同源代理,Playground 会把当前浏览器配置的 API URL 作为上游目标,并转发浏览器提供的认证头。
代理只允许以下 API 路径:
images/generationsimages/editsresponses
允许的上游源站包括:
- 已配置 Codex Provider 的 Origin。
PLAYGROUND_PROXY_ALLOWED_ORIGINS显式列出的 Origin。
Origin 只包含协议、域名或 IP 和端口,不包含 /v1 等路径。例如:
PLAYGROUND_PROXY_ALLOWED_ORIGINS=https://images.example.com,http://192.168.1.20:8080代理不会把 Codex Web 登录 Cookie 转发给上游,也不会跟随上游重定向。浏览器填写的 Authorization 会优先转发;只有目标属于已配置 Codex Provider 且浏览器没有提供 Authorization 时,服务端才会回退使用该 Provider 的凭据。未在白名单中的源站和未支持的路径会被拒绝,避免把 Codex Web 变成任意网络代理。
Image Prompt 的案例和模板保留仓库内置快照作为兜底。自动更新写入 runtime/image-prompts/,不会修改已跟踪的 vendor/ 文件;GitHub 不可用或数据校验失败时继续使用最近一次成功版本。可在 .env 中使用 IMAGE_PROMPT_AUTO_SYNC、IMAGE_PROMPT_SYNC_INTERVAL_MINUTES 和 IMAGE_PROMPT_SYNC_TIMEOUT_MS 调整更新行为。
能否实际生成图片仍取决于上游账户是否支持所选 Image 模型。网络代理正常但上游返回 model_not_found 时,需要在上游配置对应模型或切换到受支持的 Image API。
生图工作台标题栏的更新图标会检查上游稳定版。点击后,服务端在隔离的临时目录中拉取源码、应用对应的 Codex Web 集成补丁,并依次执行依赖安装、上游测试、生产构建和资源校验;全部通过后才会切换当前版本。更新期间不会覆盖仓库内置的 vendor/ 快照。
成功构建的当前版本和上一版本分别保存在 runtime/playground/current/ 与 runtime/playground/previous/。切换失败时会自动恢复旧版本;旧页面引用的 hash 资源也可从上一版本回退读取。Docker 部署已持久化 /data/runtime,因此容器重建不会丢失已安装版本。设置 PLAYGROUND_UPDATE_ENABLED=false 可禁用按钮和更新接口。
服务商配置保存在 CODEX_HOME 中,API Key 默认保存在 $CODEX_HOME/.env。Web 不会在仓库中保存真实密钥。
更新已有服务商的模型列表:
- 打开 Web 设置。
- 在 Provider 中选择服务商。
- 点击“更新模型”。
- 在 Model 下拉框中选择模型。
- 如需修改默认值,点击“设为默认模型”。
模型列表来自服务商的 <base_url>/models 接口,Web 不会按模型名称过滤。如果上游支持直接调用某个模型但没有在 /models 中返回它,该模型不会自动出现在下拉框中。
在 Web 中新增、删除服务商或保存默认模型时,服务端会重载持久 Codex App Server,并在新进程初始化完成后才返回成功,因此新 Base URL、API Key 和模型设置无需重启 Codex Web 即可用于下一次调用。为避免中断会话,存在由 App Server 执行的任务时会拒绝修改并返回 409,任务完成后可立即重试。
思考档位:
- 在设置中的 Reasoning 选择
默认、low、medium、high、xhigh或max。 - 当前选择会随每次 Web 任务显式传给 Codex App。
- 点击“设为默认模型”时,服务商、模型和思考档位会一起保存到本机 Codex 配置。
- 选择“默认”表示不覆盖档位,由模型或上游决定默认行为。
任务开始信息会显示实际传入的 reasoning 值。还可以在任务完成后检查最新 Codex 原生会话中的 turn_context:
latest=$(find "${CODEX_HOME:-$HOME/.codex}/sessions" -type f -name '*.jsonl' | sort | tail -1)
rg '"type":"turn_context"' "$latest" | tail -1其中的 effort 可确认 Codex CLI 是否收到所选档位。第三方服务商是否完整支持该档位,仍取决于其上游实现。
设置 HOMEPAGE_API_TOKEN 后,可通过只读接口 GET /api/homepage/stats 获取 Codex App 原生会话数、服务商数、默认服务商模型数、运行中任务数及当前任务名。接口同时返回按开始时间倒序排列的 runningTasks,可用于 Homepage 动态列表。请求必须携带 X-API-Token 请求头:
curl -H "X-API-Token: $HOMEPAGE_API_TOKEN" http://localhost:36354/api/homepage/statsHomepage 的 services.yaml 可使用内置 customapi 小组件:
- AI 工具:
- Codex Web:
icon: codex-web.svg
href: http://192.168.10.10:36354
widgets:
- type: customapi
url: http://192.168.10.10:36354/api/homepage/stats
headers:
X-API-Token: "替换为 HOMEPAGE_API_TOKEN"
mappings:
- field: conversations
label: 会话
format: number
- field: providers
label: 供应商
format: number
- field: models
label: 模型
format: number
- field: running
label: 运行中
format: number
- field: currentTask
label: 当前任务
format: text
- type: customapi
url: http://192.168.10.10:36354/api/homepage/stats
headers:
X-API-Token: "替换为 HOMEPAGE_API_TOKEN"
display: dynamic-list
mappings:
items: runningTasks
name: name
label: status
limit: 5第一个小组件保留统计块并显示最近开始的任务名;第二个动态列表用于展示所有并发运行任务,效果接近 Emby “正在播放”。没有任务运行时,currentTask 为“空闲”,runningTasks 为空数组。任务数据仅包含名称、状态和开始时间,不包含工作目录、提示正文或会话 ID。
模型数量按当前默认服务商的 /models 返回结果统计,并使用短期缓存,避免 Homepage 刷新时频繁访问上游。
- Web 新建和续聊都直接使用 Codex App 原生线程,不再创建独立的 Web 会话。
- 最近会话来自 Codex App 本机索引,只显示未归档的普通用户线程;归档线程、自动化任务和子代理线程不会显示。
- 已在 Codex App 打开的线程会通过桌面 IPC 由 App 自己启动续聊、引导和取消,因此 App 窗口能立即收到用户消息与流式事件。
- App 未打开对应线程或桌面 IPC 不可用时,Web 会自动回退到持久
codex app-server --stdio;新建、改名、归档与审批仍通过 app-server 写回同一原生线程。 - 历史用户消息的“从这里重新开始”会通过
thread/fork创建新线程并保留原会话;首轮消息会创建空白新线程。 - 历史分支只回退会话上下文,不会撤销已经产生的本地文件修改;原消息中的附件需要重新添加。
- 消息历史直接读取
CODEX_HOME/session_index.jsonl、CODEX_HOME/state_5.sqlite与CODEX_HOME/sessions/,通过文件监听和轮询兜底增量刷新。 - 旧版
runtime/conversations.json仅保留兼容读取,不再显示在最近会话中。 - 浏览器关闭或 SSE 连接中断后,已经启动的 Codex 任务仍会在服务端继续运行;重新打开对应会话可查看结果。
- 手机切换应用、页面恢复或 SSE 重连时会保留已有流式内容,等对应 turn 的终止记录持久化后再用完整历史替换,避免短暂只剩用户消息。
- 同一时间运行任务时,部分会话编辑操作会被暂时禁止,以避免破坏执行中的数据。
- Codex App 原生会话保存在
CODEX_HOME/state_5.sqlite、CODEX_HOME/session_index.jsonl与CODEX_HOME/sessions/ - 旧版 Web 会话可能仍保存在
runtime/conversations.json,仅作兼容数据保留 - 上传附件保存在
runtime/uploads/ - 外观设置和自定义背景保存在
runtime/下 - Image Prompt 自动更新缓存保存在
runtime/image-prompts/ - Playground 的 API 配置、历史和图片数据保存在当前浏览器站点数据中
- 服务运行日志和临时文件也应保留在本地
这些文件属于本机运行数据,不建议提交到远程仓库。
当前仓库只适合提交源码和依赖锁文件。推送前请确认:
git status --ignored应确保以下内容没有进入暂存区:
.env
runtime/
node_modules/
*.log
修改代码后运行项目检查:
npm run check提交 Pull Request 前还需要同步最新 main 并运行完整检查,具体流程见 CONTRIBUTING.md。
如服务已在后台运行,修改后需要重启进程才能生效。
⚠️ 警告:会话中途不要切换模型,会产生冲突,不稳定。