docs: update master server profile boundaries
Pipelines as Code CI / hwlab-web-probe-sentinel-nc01- Success
Pipelines as Code CI / unidesk-host- Success

This commit is contained in:
Codex
2026-07-10 19:12:09 +02:00
parent 09171c4b1d
commit 6a918d52b4
+360 -97
View File
@@ -1,126 +1,389 @@
# Master Server Ops
# Master Server 运维
This document records master-server architecture and decision rules. Installed Codex wrappers own their command syntax; this reference owns profile boundaries, safety rules and acceptance criteria. General server lifecycle and GC commands remain in the `unidesk-ops` skill. Do not place secrets, one-off incident logs, or dated changelog notes here.
本文记录 Master Server 的架构与判定规则。已安装的 Codex wrapper 负责命令语法,
本文负责 profile 边界、安全规则和验收标准。通用 server 生命周期与 GC 命令仍由
`unidesk-ops` skill 负责。禁止在本文记录 Secret、一次性故障流水或带日期的
changelog。
## Execution Boundary
## 执行边界
- The master server is the production entry point and control plane. Default work on this host is limited to light source edits, Git operations, status checks, health checks, logs, diagnostics, JSON CLI control actions, and local profile wrapper maintenance.
- Heavy builds and repository-wide checks should run on an external execution surface such as G14, D601, CI/CD, or the target runtime.
- The local UniDesk checkout at `/root/unidesk` can be used for lightweight UniDesk CLI/trans/tran/helper changes.
- Master Server 是生产入口和控制面。
- 本机默认只执行轻量源码修改、Git 操作、状态检查、健康检查、日志、诊断、
JSON CLI 控制动作和本地 profile wrapper 维护。
- 重型构建和仓库级检查必须放到 G14、D601、CI/CD 或目标运行面。
- 本机 `/root/unidesk` checkout 可用于轻量 UniDesk CLI、`trans``tran`
和 helper 修改。
## Codex Provider Profiles
## Codex Provider Profile
`mycx` and `oncx` are stable system Codex wrappers under `/usr/local/bin/`; both use the default `/root/.codex` home and are described in the shared-state subsection below. `dscx`, `mxcx`, and `acx` are isolated local Codex profile wrappers under `/root/.local/bin/`. They are host-level tools, not UniDesk service code. `acx` is the unified multi-model entry; `gocx` remains the OpenCode Zen Go compatibility entry, and older single-model `dscx-go`, `dfcx-go`, and `glcx-go` wrappers are compatibility entries.
- `mycx` `oncx` `/usr/local/bin/` 下的稳定系统 Codex wrapper。
- 两者复用同一个系统 `codex` binary。
- 两者的认证 home 已隔离,长期约束见“系统 Wrapper 与共享状态”。
- `dscx``mxcx``acx``/root/.local/bin/` 下的隔离 profile
wrapper。
- 它们是 host 级工具,不属于 UniDesk service 代码。
- `acx` 是统一多模型入口。
- `gocx` 保留为 OpenCode Zen Go 兼容入口。
- 旧的 `dscx-go``dfcx-go``glcx-go` 只保留兼容入口。
- `dscx` uses `CODEX_HOME=/root/.codex-deepseek-v4-pro`, model `deepseek-v4-pro`, Codex custom provider `deepseek`, and local Moon Bridge at `http://127.0.0.1:38440/v1`.
- `mxcx` uses `CODEX_HOME=/root/.codex-minimax-m3`, model `MiniMax-M3`, Codex custom provider `minimax`, and local Moon Bridge at `http://127.0.0.1:38441/v1`.
- `acx` uses `CODEX_HOME=/root/.codex-acx` and default model `gpt-5.5-only`. GPT aliases use Codex custom providers that connect directly to their OpenAI-compatible Responses upstreams; OpenCode Zen Go aliases still use the local ACX router only to reach `gocx`/Moon Bridge.
- `gocx` uses `CODEX_HOME=/root/.codex-opencode-go-all`, default model `glm-5.1`, Codex custom provider `opencode`, and local Moon Bridge at `http://127.0.0.1:38447/v1`.
- `dscx-go` uses `CODEX_HOME=/root/.codex-opencode-go`, model `deepseek-v4-pro`, Codex custom provider `opencode`, and local Moon Bridge at `http://127.0.0.1:38443/v1`.
- `dfcx-go` uses `CODEX_HOME=/root/.codex-opencode-flash`, model `deepseek-v4-flash`, Codex custom provider `opencode`, and local Moon Bridge at `http://127.0.0.1:38444/v1`.
- `glcx-go` uses `CODEX_HOME=/root/.codex-opencode-glm`, model `glm-5.1`, Codex custom provider `opencode`, and local Moon Bridge at `http://127.0.0.1:38446/v1`.
- `acx` includes all OpenCode Zen Go upstream slugs plus `gpt-5.5-only` and `gpt-5.5-sub2api` in one `model-catalog.json` so Codex can use `/model` or `-m <model>` within the same profile.
- `acx` routes OpenCode Zen Go models to the existing `gocx` Moon Bridge. GPT models must not pass through Moon Bridge or the ACX router: `gpt-5.5-only` uses the direct `only` OpenAI-compatible Responses endpoint and `gpt-5.5-sub2api` uses the Sub2API pool endpoint, both with upstream model `gpt-5.5`.
- GPT direct providers must receive their API key through an environment-key path such as `ACX_GPT_DIRECT_API_KEY`, read from the matching `/root/.codex/auth.json.<profile>` file by the wrapper. Do not let direct GPT calls fall back to `/root/.codex-acx/auth.json`; that file may contain only the local-router dummy key.
- Isolated Moon Bridge and router wrappers read upstream API keys from profile auth files or, where the compatibility path still requires it, wrapper-injected environment variables; generated runtime configs live under the profile `.tmp/` directory with mode `0600`. This compatibility rule does not apply to `mycx` Pika auth, whose command-backed contract is defined below. Do not copy upstream keys into documentation.
- Each profile must include `model_catalog_json` in `config.toml` pointing to a profile-local `model-catalog.json` entry for its active model. Missing catalog metadata causes Codex to fall back to default metadata, which lowers the effective context window and prints `Model metadata ... not found`.
- Profile context metadata must match the intended upstream limit closely enough for Codex auto-compact to fire before provider rejection. Keep the local profile metadata in sync with the actual model family you are routing to.
- Current master-server profile baselines:
- GPT profiles exposed through `acx` use `model_context_window = 272000` and `model_auto_compact_token_limit = 240000`. This represents the Codex-facing input window for GPT-5.5, not the larger raw API model window.
- `deepseek-v4-pro` and `deepseek-v4-flash` use `model_context_window = 1000000` and `model_auto_compact_token_limit = 900000`.
- Other local Moon Bridge profiles, including `glm-5.1`, `MiniMax-M3`, and the non-DeepSeek OpenCode models exposed through `acx`/`gocx`, use `model_context_window = 200000` and `model_auto_compact_token_limit = 180000`.
- Keep the wrapper-generated Moon Bridge/router metadata aligned with the profile `config.toml` and `model-catalog.json`. If these diverge, Codex and the local admission layer may disagree about compaction and request size behavior.
- `hyueapi.com` / `.hyueapi.com` must remain in `NO_PROXY` / `no_proxy` for Codex API channels.
- `dscx`
- 使用 `CODEX_HOME=/root/.codex-deepseek-v4-pro`
- 使用模型 `deepseek-v4-pro` Codex 自定义 provider `deepseek`
- 使用本机 Moon Bridge `http://127.0.0.1:38440/v1`
- `mxcx`
- 使用 `CODEX_HOME=/root/.codex-minimax-m3`
- 使用模型 `MiniMax-M3` Codex 自定义 provider `minimax`
- 使用本机 Moon Bridge `http://127.0.0.1:38441/v1`
- `acx`
- 使用 `CODEX_HOME=/root/.codex-acx`
- 默认模型是 `gpt-5.5-only`
- GPT alias 通过 Codex 自定义 provider 直连 OpenAI-compatible Responses 上游;
- OpenCode Zen Go alias 仍通过本机 ACX router 到达 `gocx` / Moon Bridge。
- `gocx`
- 使用 `CODEX_HOME=/root/.codex-opencode-go-all`
- 默认模型是 `glm-5.1`
- 使用 Codex 自定义 provider `opencode`
- 使用本机 Moon Bridge `http://127.0.0.1:38447/v1`
- `dscx-go`
- 使用 `CODEX_HOME=/root/.codex-opencode-go`
- 使用模型 `deepseek-v4-pro`
- 使用本机 Moon Bridge `http://127.0.0.1:38443/v1`
- `dfcx-go`
- 使用 `CODEX_HOME=/root/.codex-opencode-flash`
- 使用模型 `deepseek-v4-flash`
- 使用本机 Moon Bridge `http://127.0.0.1:38444/v1`
- `glcx-go`
- 使用 `CODEX_HOME=/root/.codex-opencode-glm`
- 使用模型 `glm-5.1`
- 使用本机 Moon Bridge `http://127.0.0.1:38446/v1`
### Shared CODEX_HOME Wrappers (`mycx` / `oncx`)
- `acx``model-catalog.json`
- 包含全部 OpenCode Zen Go upstream slug
- 包含 `gpt-5.5-only``gpt-5.5-sub2api`
- 允许在同一 profile 中通过 `/model``-m <model>` 切换。
- `acx` 的 GPT 路由:
- `gpt-5.5-only` 直连 `only` OpenAI-compatible Responses endpoint
- `gpt-5.5-sub2api` 直连 Sub2API pool endpoint
- 两者的 upstream model 都是 `gpt-5.5`
- GPT 请求禁止经过 Moon Bridge 或 ACX router。
- GPT direct provider
- 必须通过 `ACX_GPT_DIRECT_API_KEY` 一类环境键接收 API key
- wrapper 从对应的 `/root/.codex/auth.json.<profile>` 读取;
- 禁止回退到 `/root/.codex-acx/auth.json`
- `/root/.codex-acx/auth.json` 只允许保存本地 router dummy key。
- 隔离的 Moon Bridge 与 router wrapper
- 从 profile auth 文件读取 upstream API key
- 仅在兼容路径确有需要时由 wrapper 注入环境变量;
- 生成配置放在 profile 的 `.tmp/`,权限必须是 `0600`
- 此兼容规则不适用于 `mycx` 的 Pika command-backed auth。
- 每个 profile
- 必须在 `config.toml` 中设置 `model_catalog_json`
- 必须指向包含当前模型的 profile-local `model-catalog.json`
- 缺失时 Codex 会回退到默认 metadata,并输出
`Model metadata ... not found`
- Profile context metadata
- 必须与真实 upstream limit 对齐;
- 必须让 Codex auto-compact 在 provider 拒绝请求前触发。
- 当前 Master Server profile baseline
- `acx` 暴露的 GPT profile 使用
`model_context_window = 272000`
`model_auto_compact_token_limit = 240000`
- `deepseek-v4-pro``deepseek-v4-flash` 使用
`model_context_window = 1000000`
`model_auto_compact_token_limit = 900000`
- `glm-5.1``MiniMax-M3` 及其他本地 Moon Bridge profile 使用
`model_context_window = 200000`
`model_auto_compact_token_limit = 180000`
- Wrapper 生成的 Moon Bridge / router metadata
- 必须与 profile `config.toml``model-catalog.json` 对齐;
- 不一致时 Codex 与本地 admission layer 会对 compact 和请求大小产生分歧。
- Codex API 通道的 `NO_PROXY` / `no_proxy`
- 必须保留 `hyueapi.com``.hyueapi.com`
`mycx` and `oncx` reuse the same system `codex` binary and the same `/root/.codex` state tree. Their stable entrypoints are native executable wrappers, not shell functions:
### 系统 Wrapper 与共享状态(`mycx` / `oncx`
- `/usr/local/bin/mycx` selects profile `pika`; its writable profile layer is `/root/.codex/pika.config.toml`.
- `/usr/local/bin/oncx` selects profile `only`; its writable profile layer is `/root/.codex/only.config.toml`.
- `/root/.codex/config.toml` is the shared base layer, while `/root/.codex/state_5.sqlite` and `/root/.codex/sessions/**/rollout-*.jsonl` hold the shared session index and durable transcripts.
- The Webterm declaration in `config/platform-infra/webterm.yaml` starts `mycx`; wrapper path or startup changes must preserve that original entrypoint and include a Webterm launch check.
- `codex-pool configure-local` owns only the unsuffixed shared `config.toml` and `auth.json` consumer files described in `docs/reference/platform-infra.md`. It does not own the profile-v2 `pika.config.toml`, `only.config.toml`, or `auth.json.pika` files and must not regenerate them as Sub2API consumer state.
- Shell startup files must not define same-name functions that shadow these executables or regenerate profile files on launch. After changing a wrapper, existing Codex processes must be exited and existing shells must clear stale functions or start a new shell before validation.
- `mycx``oncx`
- 复用同一个系统 `codex` binary
- 使用不同的认证 `CODEX_HOME`
- 共享 SQLite session index 和 durable transcript。
- `/usr/local/bin/mycx`
- 使用 `CODEX_HOME=/root/.codex`
- 选择 profile `pika`
- 可写 profile 文件是 `/root/.codex/pika.config.toml`
- `/usr/local/bin/oncx`
- 使用 `CODEX_HOME=/root/.codex-only`
- 使用 `CODEX_SQLITE_HOME=/root/.codex`
- 选择 profile `only`
- 可写 profile 文件是 `/root/.codex-only/only.config.toml`
- `oncx` 的账号认证:
- 只使用 `/root/.codex-only/auth.json`
- `cli_auth_credentials_store` 必须是 `file`
- `forced_login_method` 必须是 `chatgpt`
- `auth.json` 权限必须是 `0600`
- wrapper 必须清理 `OPENAI_API_KEY``CODEX_API_KEY`
`CODEX_ACCESS_TOKEN``CRS_OAI_KEY`
- `oncx login``oncx login status``oncx logout` 必须直接操作
隔离 home,禁止附加仅适用于 runtime command 的 `--profile`
- `oncx` 的共享状态:
- `/root/.codex-only/sessions` 链接到 `/root/.codex/sessions`
- `/root/.codex-only/archived_sessions` 链接到
`/root/.codex/archived_sessions`
- `history.jsonl``skills``plugins` 链接到共享 home
- shell snapshot、认证文件和 profile 配置保持隔离。
- `/root/.codex/config.toml``/root/.codex/auth.json`
-`codex-pool configure-local` 管理;
- 只代表 Sub2API consumer
- 禁止作为 `oncx` 的 ChatGPT 登录凭据。
- Webterm
- `config/platform-infra/webterm.yaml` 启动 `mycx`
- wrapper path 或启动方式变更必须保留原入口并执行 Webterm launch check。
- Shell startup 文件:
- 禁止定义同名 function 覆盖这些 executable
- 禁止在启动时重新生成 profile 文件;
- wrapper 变更后,旧 Codex 进程必须退出;
- 旧 shell 必须清除残留 function 或启动新 shell后再验收。
For profile-v2, `/model` persists `model` and reasoning effort to the active profile file. The two wrappers therefore remember their last selections independently. `-m` and `-c model...` / `-c model_reasoning_effort...` are runtime overrides and must not be treated as persistent model selection. A fresh same-profile restart, a switch between profiles, and resuming an existing session are distinct behaviors and must be diagnosed separately.
- Profile-v2 持久化:
- `/model``model` 与 reasoning effort 写入当前 profile 文件;
- `mycx``oncx` 必须独立记住最后一次选择;
- `-m``-c model...``-c model_reasoning_effort...` 只允许临时覆盖;
- 新启动、profile 切换和 resume 必须分别诊断。
- Codex 官方认证边界:
- `--profile` 只覆盖 profile TOML,不隔离 `auth.json`
- file-based credential storage 的 `auth.json``CODEX_HOME` 决定;
- 账号登录与 API-key consumer 必须使用不同的 `CODEX_HOME`
- 依据见
[Codex Manual](https://developers.openai.com/codex/codex-manual.md#configuration-auth-and-models)。
Session discovery has an additional identity boundary:
- Session discovery
- 共享 SQLite 和 transcript 不保证 `/resume` 结果完全相同;
- picker 还会按 provider ID、cwd、source 和 archive state 过滤;
- provider ID 是持久化且大小写敏感的 session bucket key
- `--all` 只移除 cwd 限制,不移除 provider 限制;
- Codex 升级后必须重新验证此契约;
- resume 使用当前 profile 的有效 model、provider 和 reasoning override
- resume 不保证恢复 session 最后记录的模型。
- Rollout JSONL
- 是 durable history
- 可以重新填充 SQLite index
- 禁止只修改 `state_5.sqlite` 合并 provider bucket
- history migration 必须停止活动 Codex 进程;
- 必须用结构化 JSON parser 修改 rollout metadata
- 必须事务化更新 SQLite index
- 必须保留 provenance 并在 reindex 后验证相同 session ID 集合。
- Provider identity
- 是兼容性契约;
- 修改 `CODEX_HOME`、profile name、provider ID 或大小写前必须预检历史;
- 会产生新隐藏 bucket 时必须告警或阻断;
- 禁止让不同真实 backend 仅为合并 picker list 而冒充同一 provider。
- Sharing `CODEX_HOME` does not guarantee identical `/resume` results. The picker also filters by the effective provider ID and by cwd, source, and archive state.
- Provider IDs are persisted, case-sensitive session bucket keys. The active wrappers use distinct provider identities, and historical sessions can retain earlier capitalization or provider names.
- In the deployed picker behavior, `--all` removes the cwd restriction but does not remove the provider restriction. Revalidate this contract after Codex upgrades before changing wrappers or migrating history.
- Resume uses the current profile's effective model, provider, and reasoning overrides; it does not necessarily restore the model last recorded by the selected session. Fresh model persistence and session-model restoration must therefore have separate acceptance criteria.
- Rollout JSONL is durable history and can repopulate the SQLite index. Never change only `state_5.sqlite` to merge provider buckets. A reviewed history migration must stop active Codex processes, update rollout metadata with a structured JSON parser, update the SQLite index transactionally, preserve provenance, and verify the same session ID set after reindexing.
- Pika 认证:
- 必须使用 `[model_providers.Pika.auth]` 的 command-backed provider auth
- credential source 是 `/root/.codex/auth.json.pika`
- 文件权限必须是 `0600`
- 禁止把 Pika API key 导出到 wrapper 或 Codex 环境;
- shell snapshot 权限必须是 `0600`
- shell snapshot 禁止包含可复用 credential
- 发现 plaintext snapshot 时必须删除副本并轮换 credential。
Provider identity is a compatibility contract. Any change to `CODEX_HOME`, profile name, provider ID, or provider-ID capitalization must preflight existing history and warn or block when it would create a new hidden bucket. Do not make different real backends impersonate one provider solely to merge picker lists. The preferred future unification is a picker policy with explicit `current`, `all`, or configured aliases, visible origin-provider metadata, and an explicit continue/fork decision for cross-provider resume.
- Secret-safe 诊断只允许报告:
- 有效 `CODEX_HOME`
- wrapper path
- 当前 profile 文件;
- provider ID
- model 与 reasoning
- 按 provider 统计的 session 数量;
- credential presence 或 fingerprint
- 相关文件权限。
- Profile 持久化验收:
- 选择一个非 baseline `/model`
- 退出后重新启动相同 wrapper;
- 确认选择保持;
- 确认另一 profile 文件未变化;
- 确认临时 CLI override 不写回 profile。
- `oncx` 认证验收:
- `oncx login status` 必须显示 `Logged in using ChatGPT`
- 注入无效 API-key 环境变量后仍必须显示 ChatGPT 登录;
- `oncx exec --ephemeral '<smoke prompt>'` 必须完成真实 Responses turn
- 共享 `codex login status` 必须继续显示 Sub2API API-key 登录;
- 全程禁止输出 token 或完整 API key。
- `mycx` 认证验收:
- 对应 API-key 环境变量缺失时,Pika command-backed auth 仍必须可用。
- `/resume` 差异诊断:
- 先比较 `CODEX_HOME`、provider ID、cwd、source 和 archive filter
- 禁止在这些边界未核对前归因为 storage loss 或 cache。
Pika authentication must use command-backed provider auth from `[model_providers.Pika.auth]`, with the credential source `/root/.codex/auth.json.pika` restricted to mode `0600`. Do not export the Pika API key into the wrapper or Codex environment: inherited environment variables can be captured by shell snapshots and propagated to child tools. Shell snapshots must also be restricted to mode `0600` and must not contain reusable credentials. Treat any plaintext snapshot occurrence as credential exposure, remove the copy, and rotate the credential.
Diagnostics and validation must remain secret-safe:
- Report only effective `CODEX_HOME`, wrapper path, active profile file, provider ID, model/reasoning, session counts by provider, credential presence or fingerprint, and relevant file modes.
- Verify each profile by selecting a non-baseline `/model`, exiting, fresh-starting the same wrapper, and confirming the selection remains while the other profile file is unchanged.
- Verify a temporary CLI override does not rewrite the profile, and verify Pika command-backed auth works with the corresponding API-key environment variable absent.
- When `/resume` differs, compare `CODEX_HOME`, provider ID, cwd, source, and archive filters before attributing the result to storage loss or caching.
The investigation evidence and source-level rationale for these rules are retained in [UniDesk issue #1640](https://github.com/pikasTech/unidesk/issues/1640); this document is the authority for the active long-term contract.
相关调查证据与源码级依据保留在
[UniDesk issue #1640](https://github.com/pikasTech/unidesk/issues/1640),本文是当前长期规则的
唯一权威入口。
## Moon Bridge
Moon Bridge is installed as `/root/.local/bin/moonbridge`. The binary exposes OpenAI Responses endpoints and bridges Codex to provider-specific upstream APIs. The installed profile wrappers own bridge command syntax; this section records the supported runtime behavior.
Moon Bridge 安装在 `/root/.local/bin/moonbridge`。该 binary 暴露 OpenAI Responses
endpoint,并把 Codex 请求桥接到 provider-specific upstream API。已安装的 profile
wrapper 负责 bridge 命令语法,本文只记录运行边界。
The local source copy for the installed patched build is `/root/src/moon-bridge-sanitize`. When changing Moon Bridge, keep the change narrow, run package-level tests, build a replacement binary, back up the previous binary, then restart affected profile bridges. Default master-server build restrictions still apply.
- 已安装 patch build 的本地源码:
- 路径是 `/root/src/moon-bridge-sanitize`
- 修改时必须保持范围收敛;
- 必须运行 package-level test
- 必须构建 replacement binary
- 必须备份旧 binary
- 必须重启受影响的 profile bridge
- 仍受 Master Server 重型构建限制。
Profile architecture:
### Profile 架构
- `dscx bridge-start` renders profile config and starts Moon Bridge on `127.0.0.1:38440`.
- `mxcx bridge-start` renders profile config and starts Moon Bridge on `127.0.0.1:38441`.
- `acx route-start` renders the ACX router config and starts the local routing service on `127.0.0.1:38448` for non-GPT ACX aliases that still need the OpenCode Zen Go bridge path.
- `gocx bridge-start` renders multi-model OpenCode Zen Go profile config and starts Moon Bridge on `127.0.0.1:38447`.
- `dscx-go bridge-start` renders profile config and starts Moon Bridge on `127.0.0.1:38443`.
- `dfcx-go bridge-start` renders profile config and starts Moon Bridge on `127.0.0.1:38444`.
- `glcx-go bridge-start` renders profile config and starts Moon Bridge on `127.0.0.1:38446`.
- The wrappers start Moon Bridge with `setsid` and a profile-local PID file.
- Logs are written under `<CODEX_HOME>/logs/moonbridge/`.
- `dscx` routes DeepSeek through Moon Bridge using Anthropic-compatible upstream + `deepseek_v4` extension.
- `mxcx` routes MiniMax through Moon Bridge using `openai-response` upstream passthrough.
- `acx` routes OpenCode Zen Go models to `gocx`/Moon Bridge. `gocx`, `dscx-go`, `dfcx-go`, and `glcx-go` route OpenCode Zen Go through Moon Bridge using `openai-chat` upstream at `https://opencode.ai/zen/go/v1/chat/completions`. The Codex side remains `wire_api = "responses"` against the local Moon Bridge URL.
- `acx` routes GPT aliases directly to OpenAI-compatible Responses endpoints and must not send GPT traffic through Moon Bridge or through the local ACX router. In GPT mode, `acx status` should report `mode=gpt-direct`, `routerRequired=false`, and no listener on `127.0.0.1:38448`.
- OpenCode Zen Go model IDs must use the upstream slug, such as `glm-5.1`; display names such as `GLM-5.1` are not profile model identifiers.
- Do not keep local handwritten bridge scripts, static alternate `moonbridge.config.yml` files, or other sidecar proxy paths for OpenCode Zen Go profiles. The only supported runtime path is wrapper-generated `.tmp/moonbridge.generated.yml` plus `/root/.local/bin/moonbridge`.
- For OpenCode Zen Go profiles, set an explicit `user_agent` in the generated Moon Bridge provider config. The upstream may reject default client signatures.
- Moon Bridge now performs a local context-window admission check on the Responses path before forwarding oversized requests upstream. The expected failure shape for an oversized prompt is local HTTP `400` with `invalid_request_error` and code `context_length_exceeded`, not an upstream-translated `502 Bad Gateway`.
- Do not switch MiniMax to `openai-chat` for Codex CLI unless tool-enabled smoke proves it works.
- `dscx bridge-start`
- 渲染 profile 配置;
- `127.0.0.1:38440` 启动 Moon Bridge。
- `mxcx bridge-start`
- 渲染 profile 配置;
- `127.0.0.1:38441` 启动 Moon Bridge。
- `acx route-start`
- 渲染 ACX router 配置;
-`127.0.0.1:38448` 启动本地 routing service
- 只服务仍需 OpenCode Zen Go bridge path 的非 GPT alias。
- `gocx bridge-start`
- 渲染多模型 OpenCode Zen Go profile 配置;
- `127.0.0.1:38447` 启动 Moon Bridge。
- `dscx-go bridge-start`
-`127.0.0.1:38443` 启动 Moon Bridge
- `dfcx-go bridge-start`
-`127.0.0.1:38444` 启动 Moon Bridge。
- `glcx-go bridge-start`
-`127.0.0.1:38446` 启动 Moon Bridge。
- Wrapper 启动 bridge
- 使用 `setsid`
- 使用 profile-local PID 文件;
- 日志写入 `<CODEX_HOME>/logs/moonbridge/`
- `dscx` 路由:
- 通过 Moon Bridge 使用 Anthropic-compatible upstream
- 使用 `deepseek_v4` extension。
- `mxcx` 路由:
- 通过 Moon Bridge 使用 `openai-response` upstream passthrough。
- OpenCode Zen Go 路由:
- `acx` 把模型路由到 `gocx` / Moon Bridge
- `gocx``dscx-go``dfcx-go``glcx-go` 使用
`openai-chat` upstream
- upstream 是 `https://opencode.ai/zen/go/v1/chat/completions`
- Codex 侧保持 `wire_api = "responses"`
- `acx` GPT 路由:
- 必须直连 OpenAI-compatible Responses endpoint
- 禁止经过 Moon Bridge 或本地 ACX router
- GPT mode 下 `acx status` 必须报告 `mode=gpt-direct`
- 必须报告 `routerRequired=false`
- `127.0.0.1:38448` 不应存在 listener。
- OpenCode Zen Go model ID
- 必须使用 upstream slug,例如 `glm-5.1`
- `GLM-5.1` 一类 display name 不是 profile model identifier。
- OpenCode Zen Go bridge
- 禁止保留手写 bridge script
- 禁止保留静态替代 `moonbridge.config.yml`
- 唯一支持路径是 wrapper 生成的 `.tmp/moonbridge.generated.yml`
`/root/.local/bin/moonbridge`
- 生成的 provider 配置必须显式设置 `user_agent`
- Moon Bridge context-window admission
- oversized request 必须在本地 Responses path 被拒绝;
- 预期状态是 HTTP `400`
- 错误类型是 `invalid_request_error`
- 错误 code 是 `context_length_exceeded`
- 禁止表现为 upstream-translated `502 Bad Gateway`
- MiniMax
- 未经 tool-enabled smoke 证明可用,禁止把 Codex CLI 切到
`openai-chat`
Profile validation:
### Profile 验收
- `*-go raw-smoke` verifies the upstream OpenCode Zen Go Chat Completions API directly.
- `*-go bridge-smoke` verifies local Moon Bridge's `/v1/responses` translation path.
- `*-go exec '在吗'` verifies the actual Codex profile. Passing output must not contain `Model metadata ... not found`; latest session records should show `model_context_window` derived from the profile catalog, not fallback metadata.
- `acx status`, `acx models`, `acx gpt-only exec '在吗'`, `acx gpt-sub2api exec '在吗'`, and default `acx exec '在吗'` verify GPT direct mode. Passing GPT verification should show a real Codex Responses turn and, for repeated or resume traffic, nonzero `cached_input_tokens`; it should not require a listener on `127.0.0.1:38448`.
- For OpenCode Zen Go aliases exposed through `acx`, use `acx route-start`, `acx route-status`, `acx models`, and `acx -m <opencode-model> exec '在吗'` to verify the router-to-`gocx` path.
- `gocx raw-smoke [model]`, `gocx bridge-smoke [model]`, and `gocx -m <model> exec '在吗'` verify specific OpenCode Zen Go models. Omitting `[model]` uses the default `glm-5.1`.
- `ReasoningSummaryDelta without active item` in Codex stderr is a separate adapter noise from reasoning summary events. It is not the same failure as missing model metadata and does not by itself prove the profile is unusable.
- `*-go raw-smoke`
- 直接验证 upstream OpenCode Zen Go Chat Completions API。
- `*-go bridge-smoke`
- 验证本地 Moon Bridge 的 `/v1/responses` translation path。
- `*-go exec '在吗'`
- 验证真实 Codex profile
- 输出禁止包含 `Model metadata ... not found`
- 最新 session 必须使用 profile catalog 提供的
`model_context_window`
- ACX GPT 验收:
- 使用 `acx status``acx models`
`acx gpt-only exec '在吗'``acx gpt-sub2api exec '在吗'`
默认 `acx exec '在吗'`
- 必须完成真实 Codex Responses turn
- repeated 或 resume traffic 必须出现非零 `cached_input_tokens`
- 禁止依赖 `127.0.0.1:38448` listener。
- ACX OpenCode Zen Go alias 验收:
- 使用 `acx route-start``acx route-status``acx models`
`acx -m <opencode-model> exec '在吗'`
- 验证 router 到 `gocx` 的路径。
- `gocx` 模型验收:
- 使用 `gocx raw-smoke [model]`
- 使用 `gocx bridge-smoke [model]`
- 使用 `gocx -m <model> exec '在吗'`
- 省略 `[model]` 时默认使用 `glm-5.1`
- `ReasoningSummaryDelta without active item`
- 是 reasoning summary event 的独立 adapter noise
- 不等同于 model metadata 缺失;
- 不能单独证明 profile 不可用。
### OpenAI Responses Tool Argument Sanitizer
Moon Bridge owns the online sanitizer for MiniMax-style bad tool argument JSON on the `openai-response` passthrough path. This is the first line of defense; wrapper-level session cleanup is only for JSONL that was already corrupted before the sanitizer was installed.
- Moon Bridge
- 负责 MiniMax 风格错误 tool argument JSON 的在线 sanitizer
- 作用于 `openai-response` passthrough path
- 是第一道防线;
- wrapper-level session cleanup 只处理 sanitizer 安装前已损坏的 JSONL。
- Sanitizer
- 递归扫描 `ResponsesRequest.input`
- upstream 前修复 tool-call `arguments`
- 在 completed event 中修复 response-side `arguments`
- 禁止修改 delta chunk
- 无法恢复时回退到 `{}`
- response rewrite 必须删除 upstream `Content-Length`
Sanitizer rules: recursively scans `ResponsesRequest.input`, repairs tool-call `arguments` before upstream, repairs response-side `arguments` in completed events (not delta chunks), falls back to `{}` on unrecoverable input. Response rewriting drops upstream `Content-Length`.
## MiniMax Session 恢复
## MiniMax Session Recovery
- `mxcx`
- 为损坏的 MiniMax-backed session JSONL 提供 cleanup 与 guard layer
- wrapper 负责命令语法;
- 本节只记录行为规则。
- `mxcx resume`
- 调用 Codex 前自动执行 `session-clean``session-guard`
- 使用 `CODEX_HOME=/root/.codex-minimax-m3`
- `session-clean`
- 只处理无效 tool-call `arguments`
- 包括 malformed JSON、MiniMax sentinel text 和 schema-invalid case
- 必须保留行顺序、非 tool message、reasoning、output、token record 和
session metadata
- 禁止 compact、summarize、truncate 或 reorder transcript。
- 新的无效 `arguments`
- 必须由 Moon Bridge sanitizer 在线阻止;
- `session-clean` 只用于恢复既有损坏 session。
- `session-guard`
- 注入 `mxcx-minimax-tool-and-apply-patch-guard-v2`
- 禁止重复注入。
`mxcx` includes a cleanup and guard layer for corrupted MiniMax-backed session JSONL. The wrapper owns recovery command syntax; this section documents behavioral rules.
## MiniMax Apply-Patch 操作
- `mxcx resume` auto-runs `session-clean` + `session-guard` before invoking Codex. Uses `CODEX_HOME=/root/.codex-minimax-m3` profile.
- `session-clean` is strictly scoped to invalid tool-call `arguments`: malformed JSON, MiniMax sentinel text, and schema-invalid cases. Must preserve line order, non-tool messages, reasoning, outputs, token records, and session metadata. Must not compact/summarize/truncate/reorder transcript.
- New invalid `arguments` should be prevented online by Moon Bridge sanitizer. Use `session-clean` only to recover already-written sessions.
- `session-guard` injects `mxcx-minimax-tool-and-apply-patch-guard-v2`, avoiding duplicates.
## MiniMax Apply-Patch Operations
MiniMax-backed sessions must use the same UniDesk remote text patch contract as other agents: route first, operation second, and `apply-patch` v2 by default. The stable write shape is `trans <provider>:/absolute/workspace apply-patch < patch.diff`; read-only inspection may use `trans <provider>:/absolute/workspace nl -ba file` or equivalent bounded commands.
- If `apply-patch` reports `failed to find expected lines`, first read the exact current target block, then retry with a smaller `Update File` hunk, an `@@ <unique anchor>` hint, or multiple small hunks. This is normal stale-context recovery, not a reason to switch tools.
- Do not recover text patch failures by using `download` / `upload`, remote Python/Perl/sed heredocs, `cat >` / `tee` whole-file rewrites, or `apply-patch-v1`, unless `apply-patch` itself is unavailable or the target is non-text / bulk mechanical generated content.
- MiniMax-backed session
- 必须使用与其他 agent 相同的 UniDesk 远端文本 patch 契约;
- route 在前,operation 在后;
- 默认使用 `apply-patch` v2。
- 稳定写入形式:
- `trans <provider>:/absolute/workspace apply-patch < patch.diff`
- 只读检查:
- 使用 `trans <provider>:/absolute/workspace nl -ba file` 或同等有界命令。
- `apply-patch` 报告 `failed to find expected lines` 时:
- 先读取目标当前精确内容;
- 再用更小的 `Update File` hunk 重试;
- 或使用 `@@ <unique anchor>`
- 或拆成多个小 hunk
- 这是正常 stale-context 恢复,禁止因此切换工具。
- 文本 patch 失败时禁止使用:
- `download` / `upload`
- 远端 Python、Perl 或 sed heredoc
- `cat >``tee` 整文件覆盖;
- `apply-patch-v1`
- 仅在以下情况允许例外:
- `apply-patch` 本身不可用;
- 目标不是文本;
- 目标是批量机械生成内容。