Lisa ↔ Codex Parity
Lisa is distributed for both Claude Code and Codex. Claude is the production
path; the Codex side is derived/installed separately (see "Where Codex artifacts
live" below). When a feature surface changes on the Claude side — or when either
harness ships a new capability — the Codex side drifts. This skill is the
repeatable protocol for closing that gap by having Claude and Codex converse
until they reach parity.
It generalizes the hooks-parity pass that produced
[[reference-codex-hooks-capabilities]] — read that and the worked example below
before starting.
Core principle: empirical, not documentary
Do not trust documentation or assumptions about what Codex supports. Codex's
behavior across versions is subtle and has bitten Lisa before (e.g. plugin-
bundled hooks/hooks.json silently never runs; apply_patch passes the patch as
a string under tool_input.command, not an array). Every parity claim must be
backed by one of:
- Source-read — Codex inspects its own installed binary/source/config
schema (
codex --version, codex features list, ~/.codex/, vendored Rust
source, generated schemas).
- Runtime capture — Codex runs a real
codex exec session and observes
actual behavior (capture hook stdin, confirm a block happened, confirm
injected context reached the model).
Tag every finding [VERIFIED], [VERIFIED-BY-RUN], or [UNKNOWN]. Treat
[UNKNOWN] as "must run a test before relying on it."
Prerequisites
- The
codex CLI is installed and authed on this machine. How to drive it non-
interactively (one-shot, resume, flags, /tmp brief→answer pattern) is in
[[reference-codex-cli-collaboration]]. Key invocation:
codex exec -c mcp_servers={} -c model_reasoning_effort="high" "<prompt>",
continue with codex exec resume --last "<prompt>".
- Codex has full filesystem access here, so it can verify claims about Lisa's own
files itself and run isolated tests under a throwaway
CODEX_HOME.
The protocol
Step 1 — Inventory the Claude side
Pin down exactly what the feature surface is on the Claude side and where it
lives in the repo. Source of truth is plugins/src/ (never the generated
plugins/lisa* artifacts — see PROJECT_RULES.md). For each item record: the
event/trigger, matcher, the script/file, and which stack(s) it applies to.
Step 2 — Brief Codex; have it investigate the Codex side
Write a brief to /tmp/<topic>-brief.md listing the Claude-side items and asking
precise questions about the Codex equivalent. Have Codex write its answer to
/tmp/<topic>-answer.md. Insist on source-read and runtime capture, with
confidence tags. A good question set covers:
- Does Codex support this surface at all? Via what config mechanism and exact
schema/shape? (For hooks:
~/.codex/hooks.json / project .codex/hooks.json /
config.toml [hooks], gated by [features].codex_hooks = true — NOT a
plugin-bundled hooks.json, which does not run.)
- Map each Claude trigger/event/field to its Codex equivalent, or "no
equivalent."
- Input/output/exit contract differences (field names, tool names, blocking,
context injection shape).
- Codex-only capabilities Claude lacks (e.g.
PermissionRequest).
- Porting caveats (env vars not set, cwd, timeouts, matcher semantics).
For load-bearing or [UNKNOWN] claims, send a follow-up brief asking Codex to
run a focused test and report the command + observed output.
Step 3 — Build the gap matrix
Classify every Claude-side item into exactly one bucket:
- Has equivalent — works on Codex as-is once installed correctly.
- Needs adaptation — equivalent event exists but the contract differs (e.g.
apply_patch gives a patch body, not tool_input.file_path). Implement the
adaptation.
- No equivalent — Codex genuinely lacks it. Document it as intentionally
not ported; do not fake it.
Step 4 — Implement the missing equivalents
Make the changes under the Codex-side source of truth, then rebuild. See "Where
Codex artifacts live." Keep subtle, easy-to-get-wrong logic (envelope parsing,
output shapes) in a single shared helper so it can't drift between scripts.
Step 5 — Empirical end-to-end verification by Codex
Do not declare parity from unit tests alone. Have Codex stand up a throwaway
project (isolated CODEX_HOME), wire in the actual artifacts, run a real
codex exec session that exercises the feature, and confirm the observable
outcome (file reformatted, edit blocked + file hash unchanged, context injected,
etc.). Capture commands and outputs in /tmp/<topic>-e2e-answer.md.
Step 6 — Land it
- Add/maintain regression tests (shell hooks are testable by spawning them with
crafted JSON — see
tests/unit/codex/codex-edit-hooks.test.ts).
bun run typecheck, bun run test:unit, bun run build, and ensure the
plugin build is deterministic so bun run check:plugins passes once committed.
- Document the no-equivalent items in code comments and update the relevant
capability memory ([[reference-codex-hooks-capabilities]] and siblings) so the
next parity pass starts from current knowledge.
Where Codex artifacts live
- Skills load via the
.codex-plugin skills pointer (SKILL.md only) — see
[[reference-codex-plugin-skill-loading]]. Generated by
scripts/generate-codex-plugin-artifacts.mjs during bun run build:plugins.
- Hooks are NOT distributed via the plugin (Codex doesn't execute plugin-
bundled hooks). They are installed into the project's
.codex/hooks.json by
src/codex/hooks-installer.ts (catalog of which scripts ship per stack), with
the shell scripts in src/codex/scripts/ and a tagged-merge writer in
src/codex/hooks-merger.ts.
- MCP / settings / agents / AGENTS.md have their own installers under
src/codex/ (*-installer.ts). Check there before assuming a surface is
unported.
Known Codex capability reference (as of codex-cli 0.125.0)
Authoritative details live in [[reference-codex-hooks-capabilities]]. Quick recap:
- Hook events:
PreToolUse, PermissionRequest, PostToolUse, SessionStart,
UserPromptSubmit, Stop. No SubagentStart, SessionEnd,
Notification, PreCompact.
- Context injection:
{"hookSpecificOutput":{"hookEventName":"<event>","additionalContext":"..."}}
on SessionStart/UserPromptSubmit/PostToolUse (not PreToolUse).
- Blocking: PreToolUse exit 2 + stderr, or
permissionDecision:"deny".
- Edit tool is
apply_patch; patch body is the string tool_input.command
(parse *** Add/Update/Delete File: headers); no tool_input.file_path.
CLAUDE_PLUGIN_ROOT/CODEX_PLUGIN_ROOT are not set for hook commands.
Re-verify these against the installed Codex version at the start of each pass —
new Codex releases may add events or change contracts.
Worked example — the hooks parity pass
The canonical reference run: inventoried Lisa's bundled hooks, drove Codex to
map them to Codex events (source-read), captured the real apply_patch hook
envelope by running Codex, found the post-edit hooks silently skipped Codex's
primary edit path and the migration guard's command[1] parse was a no-op,
implemented a shared _extract-edit-paths.sh, and had Codex prove end-to-end
that format-on-edit reformats an apply_patch file and block-migration denies an
apply_patch migration edit. See src/codex/scripts/ and
tests/unit/codex/codex-edit-hooks.test.ts.
Definition of done
- Every Claude-side item is classified (has-equivalent / adapted / no-equivalent)
with at least one empirical verification backing the "works" claims.
- Implemented equivalents pass unit tests AND a real Codex
codex exec run.
- No-equivalent items are documented in code + capability memory.
typecheck, test:unit, build, and check:plugins are green.
1---2name: lisa-codex-parity3description: This skill should be used when adding or changing a Lisa feature surface (hooks, skills, agents, slash-commands, MCP servers, settings, memory) and you need the Codex distribution to reach parity with the Claude distribution. It drives the `codex` CLI in a back-and-forth conversation to investigate what Codex actually supports (source-read AND empirical runtime capture — never docs alone), builds a Claude→Codex gap matrix, implements the missing equivalents, and has Codex empirically verify the result end-to-end. Use it whenever Claude Code or Codex ships a new capability, or whenever you bundle something new into Lisa for Claude and need to mirror it for Codex.4---56# Lisa ↔ Codex Parity78Lisa is distributed for **both** Claude Code and Codex. Claude is the production9path; the Codex side is derived/installed separately (see "Where Codex artifacts10live" below). When a feature surface changes on the Claude side — or when either11harness ships a new capability — the Codex side drifts. This skill is the12repeatable protocol for closing that gap by having **Claude and Codex converse**13until they reach parity.1415It generalizes the hooks-parity pass that produced16[[reference-codex-hooks-capabilities]] — read that and the worked example below17before starting.1819## Core principle: empirical, not documentary2021**Do not trust documentation or assumptions about what Codex supports.** Codex's22behavior across versions is subtle and has bitten Lisa before (e.g. plugin-23bundled `hooks/hooks.json` silently never runs; `apply_patch` passes the patch as24a *string* under `tool_input.command`, not an array). Every parity claim must be25backed by one of:26271. **Source-read** — Codex inspects its own installed binary/source/config28 schema (`codex --version`, `codex features list`, `~/.codex/`, vendored Rust29 source, generated schemas).302. **Runtime capture** — Codex runs a real `codex exec` session and observes31 actual behavior (capture hook stdin, confirm a block happened, confirm32 injected context reached the model).3334Tag every finding `[VERIFIED]`, `[VERIFIED-BY-RUN]`, or `[UNKNOWN]`. Treat35`[UNKNOWN]` as "must run a test before relying on it."3637## Prerequisites3839- The `codex` CLI is installed and authed on this machine. How to drive it non-40 interactively (one-shot, resume, flags, `/tmp` brief→answer pattern) is in41 [[reference-codex-cli-collaboration]]. Key invocation:42 `codex exec -c mcp_servers={} -c model_reasoning_effort="high" "<prompt>"`,43 continue with `codex exec resume --last "<prompt>"`.44- Codex has full filesystem access here, so it can verify claims about Lisa's own45 files itself and run isolated tests under a throwaway `CODEX_HOME`.4647## The protocol4849### Step 1 — Inventory the Claude side5051Pin down exactly what the feature surface is on the Claude side and where it52lives in the repo. Source of truth is `plugins/src/` (never the generated53`plugins/lisa*` artifacts — see PROJECT_RULES.md). For each item record: the54event/trigger, matcher, the script/file, and which stack(s) it applies to.5556### Step 2 — Brief Codex; have it investigate the Codex side5758Write a brief to `/tmp/<topic>-brief.md` listing the Claude-side items and asking59precise questions about the Codex equivalent. Have Codex write its answer to60`/tmp/<topic>-answer.md`. Insist on source-read **and** runtime capture, with61confidence tags. A good question set covers:6263- Does Codex support this surface at all? Via what config mechanism and exact64 schema/shape? (For hooks: `~/.codex/hooks.json` / project `.codex/hooks.json` /65 `config.toml` `[hooks]`, gated by `[features].codex_hooks = true` — **NOT** a66 plugin-bundled `hooks.json`, which does not run.)67- Map each Claude trigger/event/field to its Codex equivalent, or "no68 equivalent."69- Input/output/exit contract differences (field names, tool names, blocking,70 context injection shape).71- Codex-only capabilities Claude lacks (e.g. `PermissionRequest`).72- Porting caveats (env vars not set, cwd, timeouts, matcher semantics).7374For load-bearing or `[UNKNOWN]` claims, send a follow-up brief asking Codex to75**run** a focused test and report the command + observed output.7677### Step 3 — Build the gap matrix7879Classify every Claude-side item into exactly one bucket:8081- **Has equivalent** — works on Codex as-is once installed correctly.82- **Needs adaptation** — equivalent event exists but the contract differs (e.g.83 `apply_patch` gives a patch body, not `tool_input.file_path`). Implement the84 adaptation.85- **No equivalent** — Codex genuinely lacks it. Document it as intentionally86 not ported; do not fake it.8788### Step 4 — Implement the missing equivalents8990Make the changes under the Codex-side source of truth, then rebuild. See "Where91Codex artifacts live." Keep subtle, easy-to-get-wrong logic (envelope parsing,92output shapes) in a single shared helper so it can't drift between scripts.9394### Step 5 — Empirical end-to-end verification by Codex9596Do not declare parity from unit tests alone. Have Codex stand up a throwaway97project (isolated `CODEX_HOME`), wire in the actual artifacts, run a real98`codex exec` session that exercises the feature, and confirm the observable99outcome (file reformatted, edit blocked + file hash unchanged, context injected,100etc.). Capture commands and outputs in `/tmp/<topic>-e2e-answer.md`.101102### Step 6 — Land it103104- Add/maintain regression tests (shell hooks are testable by spawning them with105 crafted JSON — see `tests/unit/codex/codex-edit-hooks.test.ts`).106- `bun run typecheck`, `bun run test:unit`, `bun run build`, and ensure the107 plugin build is deterministic so `bun run check:plugins` passes once committed.108- Document the **no-equivalent** items in code comments and update the relevant109 capability memory ([[reference-codex-hooks-capabilities]] and siblings) so the110 next parity pass starts from current knowledge.111112## Where Codex artifacts live113114- **Skills** load via the `.codex-plugin` `skills` pointer (SKILL.md only) — see115 [[reference-codex-plugin-skill-loading]]. Generated by116 `scripts/generate-codex-plugin-artifacts.mjs` during `bun run build:plugins`.117- **Hooks** are NOT distributed via the plugin (Codex doesn't execute plugin-118 bundled hooks). They are installed into the project's `.codex/hooks.json` by119 `src/codex/hooks-installer.ts` (catalog of which scripts ship per stack), with120 the shell scripts in `src/codex/scripts/` and a tagged-merge writer in121 `src/codex/hooks-merger.ts`.122- **MCP / settings / agents / AGENTS.md** have their own installers under123 `src/codex/` (`*-installer.ts`). Check there before assuming a surface is124 unported.125126## Known Codex capability reference (as of codex-cli 0.125.0)127128Authoritative details live in [[reference-codex-hooks-capabilities]]. Quick recap:129130- Hook events: `PreToolUse`, `PermissionRequest`, `PostToolUse`, `SessionStart`,131 `UserPromptSubmit`, `Stop`. **No** `SubagentStart`, `SessionEnd`,132 `Notification`, `PreCompact`.133- Context injection: `{"hookSpecificOutput":{"hookEventName":"<event>","additionalContext":"..."}}`134 on SessionStart/UserPromptSubmit/PostToolUse (not PreToolUse).135- Blocking: PreToolUse exit 2 + stderr, or `permissionDecision:"deny"`.136- Edit tool is `apply_patch`; patch body is the **string** `tool_input.command`137 (parse `*** Add/Update/Delete File:` headers); no `tool_input.file_path`.138- `CLAUDE_PLUGIN_ROOT`/`CODEX_PLUGIN_ROOT` are not set for hook commands.139140Re-verify these against the installed Codex version at the start of each pass —141new Codex releases may add events or change contracts.142143## Worked example — the hooks parity pass144145The canonical reference run: inventoried Lisa's bundled hooks, drove Codex to146map them to Codex events (source-read), captured the real `apply_patch` hook147envelope by running Codex, found the post-edit hooks silently skipped Codex's148primary edit path and the migration guard's `command[1]` parse was a no-op,149implemented a shared `_extract-edit-paths.sh`, and had Codex prove end-to-end150that format-on-edit reformats an `apply_patch` file and block-migration denies an151`apply_patch` migration edit. See `src/codex/scripts/` and152`tests/unit/codex/codex-edit-hooks.test.ts`.153154## Definition of done155156- Every Claude-side item is classified (has-equivalent / adapted / no-equivalent)157 with at least one empirical verification backing the "works" claims.158- Implemented equivalents pass unit tests AND a real Codex `codex exec` run.159- No-equivalent items are documented in code + capability memory.160- `typecheck`, `test:unit`, `build`, and `check:plugins` are green.