- name
- codex-app-parity
- description
- Use only when the user explicitly mentions Codex parity, codex-app-parity, Codex.app parity, or asks to compare against the installed Codex desktop app.
# Codex App Parity Skill
Use this skill only when the user explicitly asks for Codex parity work, names `codex-app-parity`, mentions Codex.app parity, or asks to compare behavior against the installed Codex desktop app.
Do not auto-trigger this skill for ordinary feature work, UI changes, or user-visible behavior changes unless the user explicitly requests that parity workflow.
## Objective
Ensure behavior is implemented with Codex.app as the source of truth, then verified with headless Playwright and screenshots.
## Project Instructions
## Repo Knowledge Maintenance
For user-visible Directory, Skills, Apps, Plugins, MCP, or Composio changes in this repo:
- Update the relevant manual test doc under `tests/<domain>/...` with verification steps, including light and dark theme checks. Update `tests.md` only when adding, renaming, or removing a domain folder.
- If the change creates or changes durable behavior/architecture, add or update an `llm-wiki/raw/...` source and corresponding `llm-wiki/wiki/...` concept page.
- Keep `whatToTest.md` as a short pending-only checklist; remove items that were actually executed successfully.
- Prefer assertions plus screenshots for browser validation; screenshots alone are not enough.
## Codex.app-First Development Policy
For every **new feature** and every **behavior/UI change**, treat the installed desktop app as the source of truth:
- App path: `/Applications/Codex.app`
- Primary bundle to inspect: `/Applications/Codex.app/Contents/Resources/app.asar`
Do not implement first and compare later. Compare first, then implement.
## How to Search for Features in Codex.app
### Extraction
Extract the app bundle once (reuse if already extracted):
```bash
mkdir -p /tmp/codex-app-extracted
npx asar extract "/Applications/Codex.app/Contents/Resources/app.asar" /tmp/codex-app-extracted
```
### Key Directories
| Directory | Contents |
|-----------|----------|
| `/tmp/codex-app-extracted/webview/assets/` | Main frontend bundle (`index-*.js`) + locale files |
| `/tmp/codex-app-extracted/.vite/build/` | Electron main process (`main.js`, `main-*.js`, `preload.js`, `worker.js`) |
| `/tmp/codex-app-extracted/package.json` | App metadata, version, entry point |
### Searching the Minified Bundle
The main UI bundle is a single large minified JS file at `webview/assets/index-*.js`. Use Python to search since `grep -o` with large repeat counts fails on macOS:
```python
python3 -c "
with open('/tmp/codex-app-extracted/webview/assets/index-<hash>.js', 'r') as f:
content = f.read()
idx = content.find('YOUR_SEARCH_TERM')
if idx >= 0:
print(content[max(0, idx-200):idx+500])
"
```
### What to Search For
1. **i18n keys**: Search locale files (`webview/assets/zh-TW-*.js`, `webview/assets/en-*.js`, etc.) for human-readable labels. Keys follow the pattern `component.feature.property` (e.g., `composer.dictation.tooltip`).
2. **Component functions**: Minified React components follow patterns like `function X4n({prop1:t,prop2:e,...})`. Search for the feature's i18n key to find the component that renders it.
3. **API calls and endpoints**: Search main process files (`.vite/build/main-*.js`) for endpoint URLs, auth handling, and IPC channels. Key patterns:
- `prodApiBaseUrl` → production API base (e.g., `https://chatgpt.com/backend-api`)
- `devApiBaseUrl` → dev API base (e.g., `http://localhost:8000/api`)
- `fetch-request` / `fetch-response` → IPC-proxied HTTP calls from renderer to main process
4. **Icon names**: Search for icon imports like `audiowave-dark.svg`, `book-open-dark.svg`. Icon mapping is in the main bundle around the `Hwn=Object.assign({` pattern.
5. **Keyboard shortcuts**: Search for `CmdOrCtrl+`, `Cmd+`, `keydown`, `keyCode`, or specific key names.
### Search Strategy
1. Start with **i18n locale files** — they have human-readable labels that identify features.
2. Use the i18n key to find the **component** in the main bundle.
3. Trace the component to find **hooks/composables**, **API calls**, and **event handlers**.
4. Check the **main process** bundle for any server-side proxying or Electron IPC handling.
## Mandatory CDP Frontend Inspection
For every feature UI or user-visible fix, inspect the live Codex.app frontend over Chrome DevTools Protocol before implementing. Bundle search is still useful, but it is not enough by itself when a visual/interaction surface exists.
### Required CDP Evidence
- Connect to Codex.app over CDP.
- Navigate or interact until the relevant feature UI, closest equivalent UI, or broken/fixed state is visible.
- Capture a screenshot under `output/playwright/` with a task-specific filename.
- Record in the final response:
- CDP endpoint/port
- Codex.app target URL/title
- screenshot absolute path
- what was visually confirmed
If the exact UI cannot be reached, capture the closest relevant Codex.app surface and state the gap.
## Mandatory Comparison and Fix Iteration
For every feature UI or user-visible fix, compare Codex.app against the web UI **before and after implementation**.
Required artifacts:
- `codex-reference`: Codex.app CDP screenshot of the target feature UI or closest equivalent.
- `web-before`: current web UI screenshot before code changes, showing the existing gap or missing behavior.
- `web-after`: web UI screenshot after implementation, showing the proposed parity result.
Required comparison notes:
- Before coding, write a short parity gap list from `codex-reference` vs `web-before`.
- After coding, compare `web-after` against `codex-reference`.
- Classify every notable mismatch as:
- `fixed`: matched or acceptably aligned
- `intentional deviation`: documented reason
- `needs follow-up`: not fixed in this task
- If `web-after` reveals a fixable mismatch in layout, copy, visibility, interaction, or state handling, do another implementation iteration and capture a new `web-after` screenshot.
- Do not report completion until the iteration has either resolved the mismatch or documented why it remains.
Use task-specific screenshot names under `output/playwright/`, for example:
- `output/playwright/<task>-codex-reference.png`
- `output/playwright/<task>-web-before.png`
- `output/playwright/<task>-web-after.png`
### Reliable CDP Launch Pattern
Before launching anything new, first check whether a Codex.app CDP endpoint is already available and reusable. Avoid creating additional Codex instances when an existing CDP-enabled instance already exposes a usable `app://-/index.html` page target.
Preferred reuse check:
```bash
for port in 3434 3435 9222 9223; do
if curl -fsS "http://127.0.0.1:$port/json/list" >/tmp/codex-cdp-list.json 2>/dev/null; then
python3 - <<'PY'
import json
from pathlib import Path
rows = json.loads(Path('/tmp/codex-cdp-list.json').read_text())
page = next((row for row in rows if row.get('type') == 'page' and str(row.get('url', '')).startswith('app://-/index.html')), None)
if page:
print(page['webSocketDebuggerUrl'])
PY
if [ -s /tmp/codex-cdp-list.json ]; then
echo "Reusing CDP on port $port"
break
fi
fi
done
```
If a usable target is found, reuse it and do not launch another Codex instance.
Only if no reusable CDP target exists, run the helper's separate native Codex.app debug instance so the user's normal Codex session is not interrupted and the CDP target can stay alive after tests.
In this repo, prefer the maintained helper script first. It launches an isolated native Codex.app instance by default:
```bash
bash /Users/igor/Git-projects/codex-web-local/scripts/run-codex-unpacked-debug.sh
```
The script:
- uses `open -na` with its own `--user-data-dir`, leaving the normal Codex session untouched
- auto-picks a free CDP port and verifies the app renderer target
- prints the page WebSocket URL only after an `app://-/index.html` page is live
- supports `--external-electron` only for a focused diagnostic that explicitly needs unpacked `app.asar` behavior
If the helper script fails, treat the failure as a skill maintenance signal, not just a one-off launch error:
- Inspect the failing shell script and its nearby helper scripts before using a manual fallback.
- Fix durable launcher bugs in the `.sh` scripts when the cause is clear and local to the script.
- Re-run the helper after the fix and update this skill with any new reliable launch finding.
- Use a manual launch fallback only when the script cannot be repaired safely in the current task.
Use `--verify-only` when you only need to confirm whether the current endpoints are still alive.
The helper is ready only when it prints a `Renderer target is live:` value whose
URL begins with `app://-/index.html`. A listening `/json/version` endpoint alone
does not establish that the Codex renderer has started. The helper waits for this
target and exits with status `3` if it does not appear.
Use a fresh app instance with its own profile directory:
```bash
CDP_PORT=3434
while lsof -i :"$CDP_PORT" >/dev/null 2>&1; do
CDP_PORT=$((CDP_PORT + 1))
done
CDP_PROFILE_DIR="/tmp/codex-cdp-$CDP_PORT"
mkdir -p "$CDP_PROFILE_DIR"
open -na "Codex" --args \
--remote-debugging-port="$CDP_PORT" \
--user-data-dir="$CDP_PROFILE_DIR"
until curl -fsS "http://127.0.0.1:$CDP_PORT/json/list" >/tmp/codex-cdp-list.json; do
sleep 1
done
```
If Codex.app is already running without CDP, `open -a "Codex" --args --remote-debugging-port=3434` usually does **not** enable CDP because Electron reuses the existing app instance. Restart Codex.app with the port enabled.
Fallback only when a separate instance cannot be used: restart all Codex.app processes and launch the bundle executable with `nohup`. Do not assume that executable is named `Codex`; the installed app currently uses `ChatGPT`.
```bash
CODEX_EXECUTABLE="$(find /Applications/Codex.app/Contents/MacOS -maxdepth 1 -type f -perm -111 | head -n 1)"
test -n "$CODEX_EXECUTABLE"
pkill -TERM -f "/Applications/Codex.app" 2>/dev/null || true
sleep 2
if pgrep -f "/Applications/Codex.app" >/dev/null 2>&1; then
pkill -KILL -f "/Applications/Codex.app" 2>/dev/null || true
sleep 1
fi
nohup "$CODEX_EXECUTABLE" \
--remote-debugging-port="$CDP_PORT" \
>/tmp/codex-cdp.log 2>&1 &
```
Pick the page target from `/json/list` where `type == "page"` and `url` starts with `app://-/index.html`. For Playwright screenshots, prefer `chromium.connectOverCDP("http://127.0.0.1:$CDP_PORT")`, select that page, wait briefly for React/app-server hydration, and save the screenshot.
Important caveats:
- Reuse any already-running Codex.app CDP endpoint when possible; do not spawn a second or third debug instance just because the default example uses `3434`.
- `open -na "Codex"` is required for a true separate instance; `open -a "Codex"` reuses an existing app process and often does not enable CDP flags.
- Always pass an isolated `--user-data-dir` for the debug instance to avoid profile lock contention and cross-session side effects.
- If launched via raw binary, use `nohup` or a long-lived shell; short one-shot launches can drop the CDP listener when the shell exits.
- Do not call `browser.close()` when the Codex.app session should remain open.
- In Playwright builds where `browser.disconnect()` is unavailable for CDP sessions, connect, inspect/capture, and exit the test process without `close()`; this preserves the running Codex.app instance.
- Existing helper processes can keep stale non-CDP state alive; killing all `/Applications/Codex.app` processes is more reliable than only `pkill -x Codex`.
- A packaged app can rename its macOS executable independently of its bundle name. Discover the executable under `Contents/MacOS` instead of hard-coding `Contents/MacOS/Codex`.
- CDP inspection can expose local thread titles and workspace names. Avoid pasting sensitive screenshot contents into public artifacts.
## Findings: CDP Instance Reuse (2026-04-26)
- In this workspace, parity work often happens repeatedly in the same session, so a previously launched Codex.app debug instance may already be listening on a local CDP port.
- Before using `open -na "Codex"` or starting a fresh debug profile, probe common local ports and reuse an existing endpoint when it already serves a valid `app://-/index.html` page target.
- Creating unnecessary extra Codex.app instances makes parity work noisier and can leave behind multiple stale debug profiles under `/tmp/codex-cdp-*`.
## Findings: External Electron Diagnostic Launcher (2026-05-06)
- In this workspace, the most reliable parity-debug launch path is now:
- `bash /Users/igor/Git-projects/codex-web-local/scripts/run-codex-unpacked-debug.sh`
- The helper can use external Electron for diagnostics that explicitly need direct `app.asar` execution; this is no longer the default parity path.
- Using an unpinned external Electron such as `pnpm dlx electron` can break startup because Codex.app expects Electron-41-era native resources; the current helper pins the runtime to `electron@41.2.0`.
- External-Electron startup also needs Codex’s bundled Sparkle native addon available at the external Electron resource path. The helper now prepares a shim by linking:
- `/Applications/Codex.app/Contents/Resources/native/sparkle.node`
- into the matching `pnpm dlx` Electron bundle before launch.
- Verified-good external debug state from this environment:
- browser/CDP endpoint exposed from `--remote-debugging-port`
- Node inspector endpoint exposed from `--inspect`
- WebSocket connection to the Node inspector target succeeds, not just `json/list`
- When validating a parity session, do not stop at `curl /json/list`; also confirm a real WebSocket connect to the returned `webSocketDebuggerUrl`.
## Findings: Renderer Target Gate and Renamed Bundle Executable (2026-08-12)
- On this Mac, `/Applications/Codex.app/Contents/MacOS/Codex` does not exist; the executable currently is `/Applications/Codex.app/Contents/MacOS/ChatGPT`. Raw-binary fallback commands must discover an executable from `Contents/MacOS` rather than hard-code its filename.
- The native `open -na` path is the default because it produced a stable `app://-/index.html` renderer target on port `9240` on 2026-08-12. External Electron is diagnostic opt-in only.
- `scripts/run-codex-unpacked-debug.sh` treats a matching renderer target as the launch success condition. Its `--verify-only` mode applies the same test, and its normal path exits `3` when the target does not materialize.
- Historical confirmation (2026-05-27): a separate packaged instance launched with `open -na /Applications/Codex.app --args --enable-logging --remote-debugging-port=<port>` published frontend CDP successfully. The older `app.asar` extraction plus `app.asar.unpacked` overlay was for a patched-app experiment, not the normal CDP path.
## Findings: Persisted Thread Goal UI (2026-08-12)
- Persisted goals are independent app-server state and are not included in the normal thread/read rendering model. A parity client must call `thread/goal/get` when selecting an existing thread.
- Codex.app keeps a compact status/objective bar above the composer and a Goal indicator in the composer. The pencil opens goal editing; web parity can use `thread/goal/set` and `thread/goal/clear` directly.
- Current goal statuses are `active`, `paused`, `blocked`, `usageLimited`, `budgetLimited`, and `complete`; older local helpers that omit `blocked` and `usageLimited` are stale.
- An isolated packaged-app renderer may expose `app://-/index.html` over CDP but remain on the avatar overlay or hang during screenshot capture. When the user supplies an exact current desktop screenshot, preserve it as the visual reference and explicitly report the CDP reachability gap rather than claiming the generic overlay proves the target UI.
### Architecture Notes
- **Renderer → Main Process**: The renderer uses a `Uu` HTTP client class that sends `fetch-request` IPC messages to the main process. The main process class `tle` handles these, adds auth tokens, and uses `electron.net.fetch` to make actual HTTP calls.
- **Auth**: Auth tokens come from the app-server's `getAuthStatus` RPC method (ChatGPT backend auth).
- **App-server**: A `codex app-server` child process communicating via JSON-RPC over stdin/stdout. Our bridge middleware proxies RPC calls to it.
- **Config constants**: `R7` = prodApiBaseUrl (`https://chatgpt.com/backend-api`), `I7` = devApiBaseUrl (`http://localhost:8000/api`), `C7` = originator (`Codex Desktop`).
## Required Workflow (Feature Work)
1. Identify target behavior:
- Restate what behavior is being added/changed.
- Define whether it is: data mapping, runtime event handling, UX text, visual treatment, interaction model, or all of these.
2. Inspect Codex.app before coding:
- Locate the implementation in `app.asar` (extract and search built assets as needed).
- Find relevant strings/keys/functions/components for the feature (status labels, event names, item types, summaries, collapse/expand behavior, etc.).
- Capture the closest equivalent pattern if exact parity is not present.
- Connect to the live Codex.app frontend over CDP and capture a screenshot of the target UI or closest equivalent before coding.
- Capture the current web UI before screenshot and list concrete gaps versus Codex.app.
3. Build a parity checklist from Codex.app:
Auf GitHub ansehen