codex-helper 0.5.0

A Rust-based local helper / proxy for Codex CLI traffic with multi-provider routing, usage-aware switching, filtering, and session helpers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# codex-helper(Codex CLI 本地助手 / 本地代理)


> 让 Codex CLI 走一层本地“保险杠”:  
> 集中管理所有中转站 / key / 配额,在额度用完或上游挂掉时自动切换,并提供会话与脱敏辅助工具。

> English version: `README_EN.md`

---

## 为什么需要 codex-helper?


如果你有下面这些情况,codex-helper 会很合适:

- **不想手改 `~/.codex/config.toml`**  
  手工改 `model_provider` / `base_url` 容易写坏,也不好恢复。

- **有多个中转 / 多个 key,要经常切换**  
  想把 OpenAI 官方、Packy 中转、自建中转都集中管理,并一条命令切换“当前在用”的那一个。

- **经常到 401/429 才发现额度用完**  
  希望上游额度用尽时能自动切到备用线路,而不是人工盯着报错。

- **命令行里希望“一键找回 Codex 会话”**  
  例如“给我当前项目最近一次会话,并告诉我怎么 resume”。

- **想给 Codex 加一层本地脱敏和统一日志**  
  请求先本地过滤敏感信息,再发到上游;所有请求写进一个 JSONL 文件,方便排查和统计。

---

## 一分钟上手(TL;DR)


### 1. 安装(推荐:cargo-binstall)


```bash
cargo install cargo-binstall
cargo binstall codex-helper   # 安装 codex-helper,可得到 codex-helper / ch 两个命令
```

安装成功后,`codex-helper` / `ch` 会被放到 Cargo 的 bin 目录(通常是 `~/.cargo/bin`),只要该目录在你的 `PATH` 里,就可以在任意目录直接运行。

> 如果你更习惯从源码构建:  
> `cargo build --release` → 使用 `target/release/codex-helper` / `ch` 即可。

### 2. 一条命令启动 Codex 助手(最推荐)


```bash
codex-helper
# 或更短的:

ch
```

它会自动帮你:

- 启动 Codex 本地代理,监听 `127.0.0.1:3211`- 如果在交互终端运行,会默认显示一个内置 TUI 面板(可用 `--no-tui` 关闭;按 `q` 退出);
- 对 429/5xx/网络抖动等瞬态错误在**未开始向客户端输出响应**前进行有限次数的自动重试(可配置);
- 在修改前检查 `~/.codex/config.toml`,如已指向本地代理且存在备份,会询问是否先恢复原始配置;
- 必要时修改 `model_provider``model_providers.codex_proxy`,让 Codex 走本地代理,并只在首次写入备份;
- 写入 `model_providers.codex_proxy` 时,默认设置 `request_max_retries = 0` 以避免“Codex 重试 + codex-helper 重试”叠加(你也可以在 `~/.codex/config.toml` 中手动覆盖);
- 如果 `~/.codex-helper/config.toml` / `config.json` 还没初始化,会尝试根据 `~/.codex/config.toml` + `auth.json` 推导一个默认上游(首次自动落盘默认生成 TOML);
- 用 Ctrl+C 或在 TUI 中按 `q` 退出时,尝试从备份恢复原始 Codex 配置。

从此之后,你继续用原来的 `codex` 命令即可,所有请求会自动经过 codex-helper。

---

## 常见配置:多上游自动切换


最常见、也是最“物有所值”的用法,是让 codex-helper 在多个上游之间自动切换:

- 某条线路频繁失败(例如 5xx / 连接失败);
- 或被用量提供商标记为“额度用尽”(`usage_exhausted = true`);
- 在这种情况下,LB 会优先选择同一配置下的其他 upstream 作为备份。

**关键点:主线路 + 备份线路要放在同一个配置的 `upstreams` 里,而不是拆成两个平级配置。**

示例(JSON 版本;TOML 字段基本一致):

```jsonc
{
  "version": 1,
  "codex": {
    "active": "codex-main",
    "configs": {
      "codex-main": {
        "name": "codex-main",
        "alias": null,
        "upstreams": [
          {
            "base_url": "https://codex-api.packycode.com/v1",
            "auth": { "auth_token_env": "PACKYCODE_API_KEY" },
            "tags": { "provider_id": "packycode", "source": "codex-config" }
          },
          {
            "base_url": "https://co.yes.vg/v1",
            "auth": { "auth_token_env": "YESCODE_API_KEY" },
            "tags": { "provider_id": "yes", "source": "codex-config" }
          }
        ]
      }
    }
  }
}
```

在这份配置下:

- `active = "codex-main"` → 负载均衡器会在 `upstreams[0]`(Packy)和 `upstreams[1]`(Yes)之间选择;
- 当某个 upstream:
  - 连续失败达到阈值(`FAILURE_THRESHOLD`,见 `src/lb.rs`),或
  -`usage_providers` 标记为 `usage_exhausted = true`  
  时,LB 会优先避开它,尽量选择列表中的其他 upstream;
- 所有 upstream 都被视为“不可用”时,仍会兜底返回第一个,避免完全断流。

---

## 常用命令速查表


### 日常使用


- 启动 Codex 助手(推荐):
  - `codex-helper` / `ch`
- 显式启动 Codex 代理:
  - `codex-helper serve`(默认端口 3211)
  - `codex-helper serve --no-tui`(关闭内置 TUI 面板)

### 开关 Codex


- 一次性让 Codex 指向本地代理:

  ```bash
  codex-helper switch on

  ```

- 从备份恢复原始配置:

  ```bash
  codex-helper switch off

  ```

- 查看当前开关状态:

  ```bash
  codex-helper switch status

  ```

### 配置管理(上游 / 中转)


- 列出配置:

  ```bash
  codex-helper config list

  ```

- 添加新配置:

  ```bash
  codex-helper config add openai-main \

    --base-url https://api.openai.com/v1 \

    --auth-token-env OPENAI_API_KEY \

    --alias "OpenAI 主额度"

  ```

- 切换当前 active 配置:

  ```bash
  codex-helper config set-active openai-main

  ```

### 会话、用量与诊断


- 会话助手(Codex):

  ```bash
  codex-helper session list

  codex-helper session last

  ```

- 请求用量 / 日志:

  ```bash
  codex-helper usage summary

  codex-helper usage tail --limit 20 --raw

  ```

- 状态与诊断:

  ```bash
  codex-helper status

  codex-helper doctor


  # JSON 输出,方便脚本 / UI 集成

  codex-helper status --json | jq .

  codex-helper doctor --json | jq '.checks[] | select(.status != "ok")'

  ```

---

## 典型场景示例


### 场景 1:多中转 / 多 key 集中管理 + 快速切换


```bash
# 1. 为不同供应商添加配置

codex-helper config add openai-main \
  --base-url https://api.openai.com/v1 \
  --auth-token-env OPENAI_API_KEY \
  --alias "OpenAI 主额度"

codex-helper config add packy-main \
  --base-url https://codex-api.packycode.com/v1 \
  --auth-token-env PACKYCODE_API_KEY \
  --alias "Packy 中转"

codex-helper config list

# 2. 全局选择当前使用的供应商(active 配置)

codex-helper config set-active openai-main   # 使用 OpenAI
codex-helper config set-active packy-main    # 使用 Packy

# 3. 一次性让 Codex 使用本地代理(只需执行一次)

codex-helper switch on

# 4. 在当前 active 配置下启动代理

codex-helper
```

### 场景 2:按项目快速恢复 Codex 会话


```bash
cd ~/code/my-app

codex-helper session list   # 列出与当前项目相关的最近会话
codex-helper session last   # 给出最近一次会话 + 对应 resume 命令
```

`session list` 会额外展示每个会话的轮数(rounds)与最后更新时间(last_update,优先取最后一次 assistant 响应时间)。

你也可以从任意目录查询指定项目的会话:

```bash
codex-helper session list --path ~/code/my-app
codex-helper session last --path ~/code/my-app
```

这在你有多个 side project 时尤其方便:不需要记忆 session ID,只要告诉 codex-helper 你关心的目录,它会优先匹配该目录及其父/子目录下的会话,并给出 `codex resume <ID>` 命令。

---

## 进阶配置(可选)

大部分用户只需要前面的命令即可。如果你想做更细粒度的定制,可以关注这几个文件:

- 主配置:`~/.codex-helper/config.toml`(优先)或 `~/.codex-helper/config.json`(兼容)
- 请求过滤:`~/.codex-helper/filter.json`
- 用量提供商:`~/.codex-helper/usage_providers.json`
- 请求日志:`~/.codex-helper/logs/requests.jsonl`
- 详细调试日志(可选):`~/.codex-helper/logs/requests_debug.jsonl`(仅在启用 `http_debug` 拆分时生成)
- 会话统计缓存(自动生成):`~/.codex-helper/cache/session_stats.json`(用于加速 `session list/search` 的轮数/时间统计;以 session 文件 `mtime+size` 作为失效条件,如怀疑不准可直接删除该文件强制重建)

如果你希望快速生成一个带注释的 TOML 默认模板:

```bash
codex-helper config init
```

Codex 官方文件:

- `~/.codex/auth.json`:由 `codex login` 维护,codex-helper 只读取,不写入;
- `~/.codex/config.toml`:由 Codex CLI 维护,codex-helper 仅在 `switch on/off` 时有限修改。

### 配置文件简要结构(TOML/JSON)

codex-helper 支持 `config.toml` 与 `config.json`,且字段结构基本一致;如同时存在,以 `config.toml` 为准。

```jsonc
{
  "codex": {
    "active": "openai-main",
    "configs": {
      "openai-main": {
        "name": "openai-main",
        "alias": "主 OpenAI 额度",
        "upstreams": [
          {
            "base_url": "https://api.openai.com/v1",
            "auth": {
              "auth_token": null,
              "auth_token_env": "OPENAI_API_KEY",
              "api_key": null,
              "api_key_env": null
            },
            "tags": {
              "source": "codex-config",
              "provider_id": "openai"
            }
          }
        ]
      }
    }
  }
}
```

关键点:

- `active`:当前生效的配置名;
- `configs`:按名称索引的配置集合;
- 每个 `upstream` 表示一个上游 endpoint,顺序 = 优先级(primary → backup...)。

### 用量提供商(Usage Providers)


路径:`~/.codex-helper/usage_providers.json`,示例:

```jsonc
{
  "providers": [
    {
      "id": "packycode",
      "kind": "budget_http_json",
      "domains": ["packycode.com"],
      "endpoint": "https://www.packycode.com/api/backend/users/info",
      "token_env": null,
      "poll_interval_secs": 60
    }
  ]
}
```

行为简述:

- upstream 的 `base_url` host 匹配 `domains` 中任一项,即视为该 provider 的管理对象;
- 调用 `endpoint` 的认证 token 优先来自 `token_env`,否则尝试使用绑定 upstream 的 `auth.auth_token` / `auth.auth_token_env`(运行时从环境变量解析);
- 请求结束后,codex-helper 按需调用 `endpoint` 查询额度,解析 `monthly_budget_usd` / `monthly_spent_usd`- 当额度用尽时,对应 upstream 在 LB 中被标记为 `usage_exhausted = true`,优先避开该线路。

### 请求过滤与日志


- 过滤规则:`~/.codex-helper/filter.json`,例如:

  ```jsonc
  [
    { "op": "replace", "source": "your-company.com", "target": "[REDACTED_DOMAIN]" },
    { "op": "remove",  "source": "super-secret-token" }
  ]
  ```

  请求 body 在发出前会按规则进行字节级替换 / 删除,规则根据文件 mtime 约 1 秒内自动刷新。

- 请求日志:`~/.codex-helper/logs/requests.jsonl`,每行一个 JSON,字段包括:
  - `service`(目前为 `codex`)、`method``path``status_code``duration_ms`  - `config_name``upstream_base_url`  - `usage`(input/output/total_tokens 等)。
  - (可选)`retry`:发生重试/切换上游时记录重试次数与尝试链路(便于回溯问题)。
  - (可选)`http_debug`:用于排查 4xx/5xx 时记录更完整的请求/响应信息(请求头、请求体预览、上游响应头/响应体预览等)。
  - (可选)`http_debug_ref`:当启用拆分写入时,主日志只保存引用,详细内容写入 `requests_debug.jsonl`
  你可以通过环境变量启用该调试日志(默认关闭):

  - `CODEX_HELPER_HTTP_DEBUG=1`:仅当上游返回非 2xx 时写入 `http_debug`  - `CODEX_HELPER_HTTP_DEBUG_ALL=1`:对所有请求都写入 `http_debug`(更容易产生日志膨胀);
  - `CODEX_HELPER_HTTP_DEBUG_BODY_MAX=65536`:请求/响应 body 预览的最大字节数(会截断)。
  - `CODEX_HELPER_HTTP_DEBUG_SPLIT=1`:将 `http_debug` 大对象拆分写入 `requests_debug.jsonl`,主 `requests.jsonl` 仅保留 `http_debug_ref`(推荐在 `*_ALL=1` 时开启)。

  另外,你也可以让代理在终端直接输出更完整的非 2xx 调试信息(同样默认关闭):

  - `CODEX_HELPER_HTTP_WARN=1`:当上游返回非 2xx 时,以 `warn` 级别输出一段裁剪后的 `http_debug` JSON;
  - `CODEX_HELPER_HTTP_WARN_ALL=1`:对所有请求都输出(不建议,容易泄露/刷屏);
  - `CODEX_HELPER_HTTP_WARN_BODY_MAX=65536`:终端输出里 body 预览的最大字节数(会截断)。

  注意:敏感请求头会自动脱敏(例如 `Authorization`/`Cookie` 等);如需进一步控制请求体中的敏感信息,建议配合 `~/.codex-helper/filter.json` 使用。

### 上游重试(默认 2 次尝试)

有些上游错误(例如网络抖动、429 限流、502/503/504/524、或看起来像 Cloudflare/WAF 的拦截页)可能是瞬态的;codex-helper 支持在**未开始向客户端输出响应**前进行有限次数的重试,并尽量切换到其它 upstream。

- 主配置(`~/.codex-helper/config.toml` / `config.json`)的 `retry` 段可以设置全局默认值;同名环境变量可在运行时覆盖(用于临时调试)。
- `CODEX_HELPER_RETRY_MAX_ATTEMPTS=2`:最大尝试次数(默认来自配置的 `retry.max_attempts`,最大 8;如需关闭重试请设为 1)
- `CODEX_HELPER_RETRY_ON_STATUS=429,502,503,504,524`:遇到这些状态码时允许重试(支持 `a-b` 区间,例如 `500-599`;若上游返回 `Retry-After`,会优先按其等待时间退避)
- `CODEX_HELPER_RETRY_ON_CLASS=upstream_transport_error,cloudflare_timeout,cloudflare_challenge`:按错误分类允许重试
- `CODEX_HELPER_RETRY_BACKOFF_MS=200` / `CODEX_HELPER_RETRY_BACKOFF_MAX_MS=2000` / `CODEX_HELPER_RETRY_JITTER_MS=100`:重试退避参数(毫秒)
- `CODEX_HELPER_RETRY_CLOUDFLARE_CHALLENGE_COOLDOWN_SECS=300` / `CODEX_HELPER_RETRY_CLOUDFLARE_TIMEOUT_COOLDOWN_SECS=60` / `CODEX_HELPER_RETRY_TRANSPORT_COOLDOWN_SECS=30`:对触发重试的 upstream 施加冷却(秒)

配置示例(JSON 版本):

```jsonc
{
  "retry": {
    "max_attempts": 2,
    "backoff_ms": 200,
    "backoff_max_ms": 2000,
    "jitter_ms": 100,
    "on_status": "429,502,503,504,524",
    "on_class": ["upstream_transport_error", "cloudflare_timeout", "cloudflare_challenge"],
    "cloudflare_challenge_cooldown_secs": 300,
    "cloudflare_timeout_cooldown_secs": 60,
    "transport_cooldown_secs": 30
  }
}
```

注意:重试可能导致 **POST 请求重放**(例如重复计费/重复写入)。建议仅在你明确接受这一风险、且错误大多是瞬态的场景下开启,并将尝试次数控制在较小范围内。

### 日志文件大小控制(推荐)


`requests.jsonl` 默认会持续追加,为避免长期运行导致文件过大,codex-helper 支持自动轮转(默认开启):

- `CODEX_HELPER_REQUEST_LOG_MAX_BYTES=52428800`:单个日志文件最大字节数,超过会自动轮转(`requests.jsonl``requests.<timestamp_ms>.jsonl``requests_debug.jsonl``requests_debug.<timestamp_ms>.jsonl`)(默认 50MB);
- `CODEX_HELPER_REQUEST_LOG_MAX_FILES=10`:最多保留多少个历史轮转文件(默认 10);
- `CODEX_HELPER_REQUEST_LOG_ONLY_ERRORS=1`:只记录非 2xx 请求(可显著减少日志量,默认关闭)。

这些字段是稳定契约,后续版本只会在此基础上追加字段,不会删除或改名,方便脚本长期依赖。

---

## 与 cli_proxy / cc-switch 的关系


- [cli_proxy]https://github.com/guojinpeng/cli_proxy:多服务守护进程 + Web UI,看板 + 管理功能很全面;
- [cc-switch]https://github.com/farion1231/cc-switch:桌面 GUI 级供应商 / MCP 管理器,主打“一处管理、按需应用到各客户端”。

codex-helper 借鉴了它们的设计思路,但定位更轻量:

- 专注 Codex CLI;
- 单一二进制,无守护进程、无 Web UI;
- 更适合作为你日常使用的“命令行小助手”,或者集成进你自己的脚本 / 工具链中。