Files
AgentHub/docs/superpowers/specs/2026-08-26-workspace-codex-lane-design.md
T

4.9 KiB

Codex lanes in the Workspace — design

Issue: Smartgift-AI/Claude-Code-Monitor#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 ccam-lane-<id>.
  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 <mode> --allow-dangerously-skip-permissions
         [--model M] [--effort E] [--resume SID] [prompt]

codex:
  codex [resume <uuid> | 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 <uuid> [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=<value>)
  • 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 ccam 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.