English · 简体中文
A local web panel for configuring OpenAI Codex (desktop app and CLI): switch model providers, manage API keys, curate the model catalog, and define custom subagents that each run on their own model, reasoning effort and sandbox — with a Test button that really spawns the subagent and reports which model answered.
Everything Codex needs lives in plain files (~/.codex/config.toml, models.json, agents/*.toml). Editing them by
hand is fine until one typo in a model id or reasoning effort makes a subagent silently fall back to the default agent.
This panel edits only the lines it owns, backs everything up first, and verifies the result by actually running it.
| Pain point when editing by hand | What the panel does |
|---|---|
One wrong model_reasoning_effort and spawn_agent fails; the main model then silently retries with the default agent and a model override, so your role's instructions never take effect |
The effort dropdown only lists levels the chosen model actually supports (read from models.json), and the server validates again before writing |
Rebuilding models.json usually loses per-model metadata (base_instructions, context window, reasoning levels) |
Existing entries are reused as-is; only the model set changes |
| "Did my subagent really use that model?" — guesses and vibes | Test spawns a real session with a unique marker, then reads state_5.sqlite and checks role + model + reply |
| You forget what you changed three weeks ago | Every write goes through a timestamped backup under backups/ |
This is not a router or a proxy. It manages configuration; traffic still goes straight from Codex to whatever
base_url you configure.
- Connection — edit
model,model_provider,base_url,wire_api(responses/chat), API key, reasoning effort,web_search, and the catalog path. Existing providers are listed; typing a new name creates a new block. - Model catalog — pull
/v1/modelsfrom the upstream, tick the models you want in the picker, rebuildmodels.jsonwhile preserving metadata for models you keep. - Subagents — list
~/.codex/agents/*.toml, change model / effort / sandbox per role, create and delete roles, and edit the[agents]defaults (max_threads,max_depth,default_subagent_model). - Verification — Test current config sends one tiny request with the live configuration; Test on a role spawns it for real and reports the model that actually answered.
- Safety — binds
127.0.0.1only, requires a random per-launch token in the URL and headers, never echoes a full API key (last 4 characters only), and writes backups before touching anything.
- Windows 10 / 11 (process detection and the restart button use
tasklist/taskkill) - Python 3.11+ —
tomllibis used to read agent files. No third-party packages. - Codex installed (desktop app or CLI). If
codexis not onPATH, setCODEX_PANEL_CLIto the executable.
git clone https://github.com/<you>/codex-config-panel.git
cd codex-config-panel
start-panel.batThe browser opens http://127.0.0.1:8792/?t=<random-token>. Close the tab when done; the panel exits from its own
Exit panel button (or Ctrl+C if you started it in a terminal).
Optional environment variables:
| Variable | Default | Purpose |
|---|---|---|
CODEX_HOME |
~/.codex |
Where config.toml, models.json, agents/, state_5.sqlite live |
CODEX_PANEL_CLI |
auto-detect | Path to codex.exe / codex used for real spawn tests |
CODEX_PANEL_LAUNCHER |
auto-detect | Path to the desktop launcher, used by the Restart Codex button |
Command line: python panel.py [--port 8792] [--no-open]
| Path | How it is written |
|---|---|
<CODEX_HOME>/config.toml |
Line-level replacement of the keys it owns. [desktop], plugins, MCP servers and other provider blocks are left byte-for-byte alone — saving the same values twice leaves the file's md5 unchanged. |
<CODEX_HOME>/models.json |
Rebuilt from the ticks in the panel; kept models keep all of their metadata. |
<CODEX_HOME>/agents/<role>.toml |
Written whole (it is a small file you authored through the UI). |
backups/<timestamp>-<tag>/ |
Copy of every file the operation is about to touch. |
To roll back: copy the files from the matching backups/ folder back into CODEX_HOME, then restart Codex.
Codex supports custom subagents natively — no plugin, no proxy. A role is a small TOML file:
name = "reviewer"
description = "Use when you need an independent code review of a diff or module." # how the main model picks it
model = "glm-5.3"
model_provider = "Local_api"
model_reasoning_effort = "high"
sandbox_mode = "read-only"
nickname_candidates = ["Reviewer"]
developer_instructions = """
You review code. Report file:line, trigger conditions and a minimal fix. Never edit files.
"""| Field | Notes |
|---|---|
name |
[a-z][a-z0-9_-]*, must match the file name |
description |
The only signal the main model uses when choosing a role. Write it as "use when …" |
model / model_provider |
Must exist in your config.toml provider blocks and be served by that endpoint |
model_reasoning_effort |
Must be one of the model's supported_reasoning_levels in models.json |
sandbox_mode |
read-only / workspace-write / danger-full-access — read-only roles cannot write files at all |
nickname_candidates |
Cosmetic display names for spawned threads |
Global defaults live in config.toml:
[agents]
max_threads = 4 # concurrent subagents
max_depth = 1 # subagents cannot spawn further subagents
default_subagent_model = "glm-5.3" # fallback when a role has no model / spawn degraded
default_subagent_reasoning_effort = "low"- Name it (reliable):
Spawn reviewer to check this diff·Use vision to read this screenshot: D:\shots\ui.png - Let it choose (unreliable on its own): phrase the task and hope. In testing, a plain "review this file" made the main model do the work itself without spawning anything.
- Make it a rule: put the routing rules into
~/.codex/AGENTS.md(loaded into every session). That is the only reliable way to get automatic delegation.
- 需要看图 / 截图 / UI 稿 → 必须 spawn vision
- 代码审查 / 找 bug / 安全 → 先 spawn reviewer,再整合结论
- 读整个仓库 / 大量日志 → 先 spawn scout
- 写测试 / 复现 bug → 交给 tester
- Effort mismatch fails quietly.
spawn_agentrejects an unsupported level; the main model then retries withagent_type=defaultplus a model override. The model looks right but the role'sdeveloper_instructionswere never applied. Symptom:threads.agent_roleisdefault(or null) instead of your role name. - Changes need a restart. Agent files and
[agents]are read when Codex starts. Edit → restart Codex → new chat. An already-open conversation keeps the old picture. - Subagents do not see the parent conversation. Only the task text you write plus whatever files they read. Pass absolute paths, scope, and acceptance criteria; do not paste whole files into the task.
max_depth = 1means a subagent cannot delegate further. Do not design nested hierarchies.- Read-only roles cannot write — no permission prompt, no exception, the write simply fails.
- Catalog curation is dangerous for old chats. Unticking a model removes it from the picker, and threads that recorded that model id will report "model not found".
Four conditions must all hold, otherwise it reports which one failed:
codex execexits with code 0- a new thread row appears with
agent_roleequal to the role name - that thread's
modelequals themodelin the role file - the output contains the freshly generated
PING-<role>-<random>marker
Failure classes are separated on purpose: state database unreachable / non-zero exit / nothing spawned (the original Codex error is quoted back) / spawned but degraded to the default agent.
| Symptom | Cause / fix |
|---|---|
model provider 'X' not found when reopening an old chat |
The thread recorded a provider id that no longer exists in config.toml. Add the provider block back (point it at the same endpoint) — do not edit Codex's SQLite stores. |
HTTP 413 from a local gateway |
The gateway's request-body cap, not Codex. Raise it in the gateway's launcher, or read less per turn. |
Picker shows fewer models than /v1/models returns |
models.json is a curated catalog; use the panel's catalog card to re-tick. |
| Requests 404 | base_url is missing /v1. |
| Panel says the token is invalid | The server restarted; open it again from the shortcut, which picks up the current token. |
| Port already in use | A second launch just opens the browser at the running instance. |
| Restart button does nothing | Codex's launcher was not found: set CODEX_PANEL_LAUNCHER. |
- Windows-only in practice: process detection and the restart button shell out to
tasklist/taskkill. - The UI is Chinese; code comments and messages are Chinese too. i18n PRs welcome.
- Single upstream only, by design. Mixing several APIs into one picker needs a routing layer, which this project deliberately does not include.
- No packaging: run it from source. ~1 file backend, ~1 file frontend, no dependencies.
- OpenAI Codex — the agent this configures. This project is unaffiliated with OpenAI.
- No third-party code is vendored;
panel.pyis standard library only.
