Codex QA
QA the omo Codex Light edition (packages/omo-codex/, shipped as lazycodex). We
exercise OUR plugin in a REAL Codex while touching nothing of the user's setup:
an isolated CODEX_HOME + a local mock model means no real API call and the real
~/.codex is never read or written. Each helper script ships a --self-test
that asserts its scenario against the live machine, so the scripts are both the
QA tools and their own regression checks.
Verified against codex-cli 0.140.0 (node, jq, tmux, bun on macOS). Confirm with
codex --version; check a flag with codex <cmd> --help.
Golden rules (read before running anything)
- QA ONLY our plugin. Everything that spawns codex uses an isolated
CODEX_HOME (created by cqa_mk_isolated_home) and a LOCAL mock model
provider (cqa_start_mock). Never QA against the real ~/.codex, never hit a
real model API. The bundled scripts enforce this; if you run codex by hand,
export CODEX_HOME="$(mktemp -d)/codex"; mkdir -p "$CODEX_HOME" FIRST (a set
CODEX_HOME must already exist or codex hard-errors).
- Prove the real home stayed clean. Every script shasums
~/.codex/config.toml before and after and asserts it is unchanged. If you
script by hand, do the same.
- The interactive
codex is a shell function that injects --profile quotio.
Bash scripts bypass it and get the real binary; never rely on the interactive
alias. See references/isolation.md.
- The first-party way to prove a hook fired is the app-server notification
stream (
hook/started / hook/completed), not log scraping. See
references/app-server.md.
- The captured JSON / pane IS the evidence — write it under
.omo/evidence/<YYYYMMDD>-<slug>/ (no evidence file == the QA did not happen).
Setup
cd <this-skill-dir> # .agents/skills/codex-qa
bash scripts/lib/common.sh --self-check # confirm deps + isolation harness
Docker is the default QA surface. Run this QA inside a disposable container
that has the latest codex and a copy of your config, with the host ~/.codex
untouched: script/agent/qa-docker.sh (see references/docker-qa.md).
The local scripts below are the fallback for when Docker is unavailable or on
Windows.
Router: pick your case
| You need to… |
Run |
Deep dive |
| Prove a plugin hook fires in a LIVE Codex turn (first-party) |
scripts/app-server-drive.sh --plugin |
app-server.md |
| Prove the app-server driver itself works (no plugin, fast) |
scripts/app-server-drive.sh --self-test |
app-server.md |
| Install the LOCAL build into an isolated home + assert it landed |
scripts/install-verify.sh --self-test |
install-verify.md |
| Pin ONE component's hook logic deterministically (no codex) |
scripts/hook-unit-probe.sh --self-test |
components-hooks.md |
| Smoke the real TUI under tmux (boots, renders, survives) |
scripts/tui-smoke.sh --self-test |
logging-debug.md |
| Watch runtime logs while QAing |
(see reference; RUST_LOG / logs DB / /debug-config) |
logging-debug.md |
Scripts index (each is its own regression test)
| Script |
--self-test asserts |
scripts/lib/common.sh --self-check |
deps present; isolated CODEX_HOME is created inside a sandbox and auto-removed on exit; mock model serves the Responses SSE; real ~/.codex unchanged |
scripts/app-server-drive.sh |
--self-test: a bare turn completes and the mock assistant text comes back. --plugin: installs local omo, drives a turn, and asserts hook/completed for sessionStart,userPromptSubmit |
scripts/install-verify.sh |
local omo installs into the isolated home; config.toml enables omo@sisyphuslabs; component bins + agent TOMLs linked in the sandbox; real ~/.codex unchanged |
scripts/hook-unit-probe.sh |
the ultrawork component injects <ultrawork-mode> on an ulw UserPromptSubmit (also a manual --component/--event mode) |
scripts/tui-smoke.sh |
the real codex TUI boots in the isolated home, renders, and survives (no early exit); captures the pane |
When TUI visual QA evidence is needed, follow
docs/reference/web-terminal-visual-qa.md: render the TUI through the real
xterm.js web terminal - NEVER the tmux capture-pane frame, which degrades
color and CJK width:
node script/qa/web-terminal-visual-qa.mjs --title "Codex TUI QA" \
--command "codex" --input "{Enter}" \
--evidence-dir .omo/evidence/<slug>/codex-web-terminal
The helper runs a real pty, renders it in xterm.js under Chrome, and writes
terminal.txt, terminal-ansi.txt, terminal.png (true color), and
metadata.json (--from-file <capture.ansi> replays a saved raw stream). Use
that artifact set for TUI visual QA; use app-server-drive.sh --plugin for
assertion-grade hook behavior.
Match QA to your change scope
- Component / hook logic (
packages/omo-codex/plugin/components/*):
hook-unit-probe.sh for the exact stdout, THEN app-server-drive.sh --plugin
to prove the live wiring. See components-hooks.md.
- Installer / config.toml (
packages/omo-codex/src/install/*):
install-verify.sh.
- Anything that affects a live session (hooks, agents, MCP wiring):
app-server-drive.sh --plugin, and tui-smoke.sh --plugin if the TUI path
matters.
Capturing evidence
ev=".omo/evidence/$(date +%Y%m%d)-codex-qa-<slug>"; mkdir -p "$ev"
bash scripts/app-server-drive.sh --plugin > "$ev/app-server-drive.json" 2>&1
bash scripts/install-verify.sh --self-test > "$ev/install-verify.txt" 2>&1
On /debugging
There is no /debugging command in Codex. To observe a run: the app-server
notification stream (above), RUST_LOG=debug on the app-server's stderr, the
logs SQLite under $CODEX_HOME, the TUI's /debug-config, and the
codex debug … subcommands. See logging-debug.md.
1---2name: codex-qa3description: QA the omo Codex Light edition (lazycodex / packages/omo-codex) itself, in strict isolation so ONLY our plugin is exercised, never the user's real ~/.codex. The first-party method drives the real `codex app-server` against an isolated CODEX_HOME plus a LOCAL mock model (no real API call), and proves a plugin hook fired by asserting hook/started + hook/completed notifications. Also: isolated install verification, per-component hook probes, a tmux TUI smoke, and runtime log observation (RUST_LOG / logs SQLite / /debug-config). Ships tested helper scripts each with a --self-test. Use whenever someone changes anything under packages/omo-codex or wants to QA, smoke-test, verify, or debug the Codex plugin, its hooks/components, the installer/config.toml, the app-server flow, or the Codex TUI. Triggers: codex qa, qa codex, codex-qa, test codex plugin, verify codex hook, codex app-server, lazycodex qa, isolated CODEX_HOME, prove codex hook fired, codex tui test.4---5
6# Codex QA
7
8QA the omo Codex Light edition (`packages/omo-codex/`, shipped as lazycodex). We
9exercise OUR plugin in a REAL Codex while touching nothing of the user's setup:
10an isolated `CODEX_HOME` + a local mock model means no real API call and the real
11`~/.codex` is never read or written. Each helper script ships a `--self-test`
12that asserts its scenario against the live machine, so the scripts are both the
13QA tools and their own regression checks.
14
15Verified against `codex-cli 0.140.0` (node, jq, tmux, bun on macOS). Confirm with
16`codex --version`; check a flag with `codex <cmd> --help`.
17
18## Golden rules (read before running anything)
19
20- **QA ONLY our plugin.** Everything that spawns codex uses an isolated
21 `CODEX_HOME` (created by `cqa_mk_isolated_home`) and a LOCAL mock model
22 provider (`cqa_start_mock`). Never QA against the real `~/.codex`, never hit a
23 real model API. The bundled scripts enforce this; if you run codex by hand,
24 `export CODEX_HOME="$(mktemp -d)/codex"; mkdir -p "$CODEX_HOME"` FIRST (a set
25 `CODEX_HOME` must already exist or codex hard-errors).
26- **Prove the real home stayed clean.** Every script shasums
27 `~/.codex/config.toml` before and after and asserts it is unchanged. If you
28 script by hand, do the same.
29- **The interactive `codex` is a shell function** that injects `--profile quotio`.
30 Bash scripts bypass it and get the real binary; never rely on the interactive
31 alias. See [references/isolation.md](references/isolation.md).
32- **The first-party way to prove a hook fired is the app-server** notification
33 stream (`hook/started` / `hook/completed`), not log scraping. See
34 [references/app-server.md](references/app-server.md).
35- **The captured JSON / pane IS the evidence** — write it under
36 `.omo/evidence/<YYYYMMDD>-<slug>/` (no evidence file == the QA did not happen).
37
38## Setup
39
40```bash
41cd <this-skill-dir> # .agents/skills/codex-qa
42bash scripts/lib/common.sh --self-check # confirm deps + isolation harness
43```
44
45**Docker is the default QA surface.** Run this QA inside a disposable container
46that has the latest codex and a copy of your config, with the host `~/.codex`
47untouched: `script/agent/qa-docker.sh` (see [references/docker-qa.md](references/docker-qa.md)).
48The local scripts below are the fallback for when Docker is unavailable or on
49Windows.
50
51## Router: pick your case
52
53| You need to… | Run | Deep dive |
54|---|---|---|
55| Prove a plugin hook fires in a LIVE Codex turn (first-party) | `scripts/app-server-drive.sh --plugin` | [app-server.md](references/app-server.md) |
56| Prove the app-server driver itself works (no plugin, fast) | `scripts/app-server-drive.sh --self-test` | [app-server.md](references/app-server.md) |
57| Install the LOCAL build into an isolated home + assert it landed | `scripts/install-verify.sh --self-test` | [install-verify.md](references/install-verify.md) |
58| Pin ONE component's hook logic deterministically (no codex) | `scripts/hook-unit-probe.sh --self-test` | [components-hooks.md](references/components-hooks.md) |
59| Smoke the real TUI under tmux (boots, renders, survives) | `scripts/tui-smoke.sh --self-test` | [logging-debug.md](references/logging-debug.md) |
60| Watch runtime logs while QAing | (see reference; RUST_LOG / logs DB / `/debug-config`) | [logging-debug.md](references/logging-debug.md) |
61
62## Scripts index (each is its own regression test)
63
64| Script | `--self-test` asserts |
65|---|---|
66| `scripts/lib/common.sh --self-check` | deps present; isolated `CODEX_HOME` is created inside a sandbox and auto-removed on exit; mock model serves the Responses SSE; real `~/.codex` unchanged |
67| `scripts/app-server-drive.sh` | `--self-test`: a bare turn completes and the mock assistant text comes back. `--plugin`: installs local omo, drives a turn, and asserts `hook/completed` for `sessionStart,userPromptSubmit` |
68| `scripts/install-verify.sh` | local omo installs into the isolated home; `config.toml` enables `omo@sisyphuslabs`; component bins + agent TOMLs linked in the sandbox; real `~/.codex` unchanged |
69| `scripts/hook-unit-probe.sh` | the `ultrawork` component injects `<ultrawork-mode>` on an `ulw` UserPromptSubmit (also a manual `--component/--event` mode) |
70| `scripts/tui-smoke.sh` | the real codex TUI boots in the isolated home, renders, and survives (no early exit); captures the pane |
71
72When TUI visual QA evidence is needed, follow
73`docs/reference/web-terminal-visual-qa.md`: render the TUI through the real
74xterm.js web terminal - NEVER the `tmux capture-pane` frame, which degrades
75color and CJK width:
76
77```bash
78node script/qa/web-terminal-visual-qa.mjs --title "Codex TUI QA" \
79 --command "codex" --input "{Enter}" \
80 --evidence-dir .omo/evidence/<slug>/codex-web-terminal
81```
82
83The helper runs a real pty, renders it in xterm.js under Chrome, and writes
84`terminal.txt`, `terminal-ansi.txt`, `terminal.png` (true color), and
85`metadata.json` (`--from-file <capture.ansi>` replays a saved raw stream). Use
86that artifact set for TUI visual QA; use `app-server-drive.sh --plugin` for
87assertion-grade hook behavior.
88
89## Match QA to your change scope
90
91- **Component / hook logic** (`packages/omo-codex/plugin/components/*`):
92 `hook-unit-probe.sh` for the exact stdout, THEN `app-server-drive.sh --plugin`
93 to prove the live wiring. See [components-hooks.md](references/components-hooks.md).
94- **Installer / config.toml** (`packages/omo-codex/src/install/*`):
95 `install-verify.sh`.
96- **Anything that affects a live session** (hooks, agents, MCP wiring):
97 `app-server-drive.sh --plugin`, and `tui-smoke.sh --plugin` if the TUI path
98 matters.
99
100## Capturing evidence
101
102```bash
103ev=".omo/evidence/$(date +%Y%m%d)-codex-qa-<slug>"; mkdir -p "$ev"
104bash scripts/app-server-drive.sh --plugin > "$ev/app-server-drive.json" 2>&1
105bash scripts/install-verify.sh --self-test > "$ev/install-verify.txt" 2>&1
106```
107
108## On `/debugging`
109
110There is no `/debugging` command in Codex. To observe a run: the app-server
111notification stream (above), `RUST_LOG=debug` on the app-server's stderr, the
112logs SQLite under `$CODEX_HOME`, the TUI's `/debug-config`, and the
113`codex debug …` subcommands. See [logging-debug.md](references/logging-debug.md).