# Codex lanes in the Workspace — design Issue: [Smartgift-AI/Claude-Code-Monitor#10](https://git.smartgift.io.vn/Smartgift-AI/Claude-Code-Monitor/issues/10) — "Workspace | Thêm Codex vào trang Workspace". ## Goal A lane can be driven by the `codex` CLI instead of `claude`, started and watched from the Workspace page exactly like today: same lane strip, same pipeline map, same tmux-backed terminal console, same run history. ## Decisions (from brainstorming) 1. Scope: run Codex in the lane's tmux pane. No ingestion of `~/.codex` history. 2. The tool belongs to the **lane**, not to the run: one lane = one tool, picked in the "Add lane" modal, not changeable afterwards. One tmux session per lane stays `agenthub-lane-`. 3. Codex run controls: model, sandbox, ask-for-approval, reasoning effort. 4. Codex runs persist in `dashboard_runs` (new `tool` column) so Active runs and Run history show them next to Claude runs. 5. The rest of the Workspace UI is unchanged. ## Data model `server/db.js`, following the existing `ALTER TABLE lanes ADD COLUMN` pattern (idempotent, try/catch on "duplicate column"): - `lanes.tool TEXT NOT NULL DEFAULT 'claude'` — `'claude' | 'codex'`. - `dashboard_runs.tool TEXT NOT NULL DEFAULT 'claude'`. Both default to `'claude'`, so every existing row keeps today's behavior and no response shape changes for existing consumers — `tool` is an added field. `server/lib/lanes.js` accepts `tool` on create (`ensureLane`, worktree create), validates it against `{claude, codex}`, and exposes it on the lane payload. `updateLane` never writes `tool` — a lane's tool is immutable, same spirit as "adopted lanes are not destroyable". ## Spawn `server/lib/pty-run.js` — `buildArgv({tool, ...})` branches: ``` claude (unchanged): claude --permission-mode --allow-dangerously-skip-permissions [--model M] [--effort E] [--resume SID] [prompt] codex: codex [resume | resume --last] [-m MODEL] [-s SANDBOX] [-a APPROVAL] [-c model_reasoning_effort=EFFORT] [prompt] ``` Notes: - `resume` is a **subcommand** for Codex, so it comes first, before the flags. `codex resume [prompt]`; with no recorded id, `codex resume --last`. - Allowlists (reject with `EBAD*` like today, never pass through): - sandbox: `read-only | workspace-write | danger-full-access` - approval: `on-request | never` - effort: `low | medium | high | xhigh` (Codex has no `--effort` flag; it is passed as `-c model_reasoning_effort=`) - The `--dangerously-bypass-approvals-and-sandbox` and `--dangerously-bypass-hook-trust` flags are never emitted. - `spawnRun` takes `tool` and records it on the run row. tmux session naming, create-or-adopt, and the shell-prompt send path are untouched. ## API - `POST /api/lanes/ensure`, `POST /api/lanes/worktree`: accept optional `tool`. - `POST /api/lanes/:id/start`: accepts `sandbox` and `approval` in addition to today's `model`/`effort`/`permissionMode`/`resume`. The **server reads the tool from the lane row**, never from the request body, and ignores the fields that do not belong to that tool. - `GET /api/run/binary?tool=codex`: probes `codex` on PATH (`which`), same `{found, path}` shape. Default (no query) stays `claude`. ## UI - `AddLaneModal`: a second segmented toggle "Claude Code | Codex" using the existing `Seg` component, next to the Repo/Worktree toggle. - `LaneCard` / `LaneStripCard`: a small tool badge, shown only for `codex` lanes so Claude lanes look exactly as before. - `RunSetup`: fields switch on the selected lane's `tool`. - claude: model, permission mode, effort (unchanged) - codex: model, sandbox, approval, reasoning effort - Codex lanes hide the Claude session picker (the sessions table holds Claude sessions only) and offer a single "Resume last" action mapping to `codex resume --last`. - The Start button's disabled state uses the per-tool binary probe. - Console, pipeline map, split view, run history: unchanged. - All new strings go through i18n, no literals. ## Known limitations (documented, not fixed here) Codex does not emit this dashboard's Claude Code hooks, so for a Codex lane: - Sessions, Analytics, and cost stay empty — nothing ingests Codex usage. - `server/lib/stage-detect.js` never paints the amber detected badge. - Pipeline stages still work when the agent calls `agenthub stage` itself (the repo already ships `AGENTS.md` and `.codex/`). - Lane liveness for Codex lanes comes from the tmux pane plus `dashboard_runs`. ## Testing - `npm run test:server`: Codex argv shape (fresh, resume-by-id, resume-last, effort mapping), allowlist rejections, `tool` persisted on lane and run, start route ignoring foreign fields. - `npm run test:client`: `RunSetup` field set per tool, `AddLaneModal` tool choice reaching the API call, screen snapshots reviewed and regenerated. - Docs to update: `docs/LANES.md` (tool per lane, Codex limitations), `docs/API.md` (new fields), `README` lane section if it lists lane fields.