This is the advanced operational runbook for Enhanced mode (fix-app-bugs optional addon).
For default standalone usage, start with README.md and follow Core mode.
- Stay in
Core modefor exploratory local debugging and fast manual loops. - Auto-select
Enhanced modewhen audit-ready evidence, final parity sign-off, CI/release sign-off evidence, or strict 5-block reporting is required. - If guarded bootstrap returns
canInstrumentFromBrowser = falseorbootstrap.status = fallback, runterminal-probeimmediately. - For visual parity, generate one artifact bundle per checkpoint and keep at least one headed validation.
- If parity stalls for 3 cycles or 90 minutes, stop tuning and move to rollback + retrospective planning.
- Every run must log
Mode selected + reason.
extensions/humans-debugger(MV3 extension)src/agent(local Node.js agent)logs/browser-debug(JSONL logs + screenshots)
Each target project should keep:
<project-root>/.codex/browser-debug.json
Example:
{
"version": 1,
"projectId": "my-project",
"appUrl": "http://localhost:5173",
"agent": {
"host": "127.0.0.1",
"corePort": 4678,
"debugPort": 7331
},
"browser": {
"cdpPort": 9222
},
"capture": {
"allowedDomains": ["localhost"],
"networkAllowlist": []
},
"defaults": {
"queryWindowMinutes": 30
}
}- Install deps:
npm install- Start agent:
npm run agent:start- Start Chromium with CDP enabled (example):
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222- Load unpacked extension from:
extensions/humans-debugger
GET http://127.0.0.1:4678/healthGET http://127.0.0.1:4678/runtime/configPOST http://127.0.0.1:4678/runtime/configPOST http://127.0.0.1:4678/session/startPOST http://127.0.0.1:4678/session/ensure(start or reuse active session)POST http://127.0.0.1:4678/session/stopPOST http://127.0.0.1:4678/events(requiresX-Ingest-Token)POST http://127.0.0.1:4678/commandGET http://127.0.0.1:4678/events/query
/health includes readiness fields:
readiness.debug: debug API registered.readiness.query: query API registered.readiness.cdp: deep probe result forhttp://127.0.0.1:<cdpPort>/json/version.readiness.cdpReason: probe error when unavailable.readiness.cdpPort: active runtime CDP port.appUrlDrift: config-vs-active-tab drift hint with arecommendedCommandtemplate (--project-root <project-root>) when mismatch is detected.runReadiness: canonical run verdict (runnable,fallback,blocked) withmodeHint,reasons, and optionalnextAction.
Use compatibility endpoint:
POST http://127.0.0.1:7331/debug
Preflight endpoint:
OPTIONS http://127.0.0.1:7331/debug
Supported payload:
{
"marker": "BUGFIX_TRACE",
"tag": "checkout-submit",
"event": "before-submit",
"traceId": "9b2a...",
"ts": "2026-02-06T13:00:00.000Z",
"data": {
"isValid": false,
"missingFields": 2
}
}Rules:
markermust beBUGFIX_TRACE.- Missing
tsis filled by the server. - Missing
sessionIdmaps to active session ormanual-YYYY-MM-DD. - Content types:
application/jsonandtext/plain(JSON string body). - Preflight responses are deterministic:
- allowlisted origin ->
204withAccess-Control-Allow-*. - blocked origin ->
403withCORS_POLICY_BLOCKED_PATH.
- allowlisted origin ->
Ensure CODEX_HOME is set:
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"If this run was auto-invoked by a workflow/reviewer skill, use the shared routing contract as control-plane input:
$CODEX_HOME/skills/workflows-shared/references/auto-routing-contract.md$CODEX_HOME/skills/workflows-shared/references/auto-routing-capability-map.md
Auto-routing control rules:
EVERY_AUTO_ROUTING_ENABLED=falsemeans no auto invocation is allowed.- Session opt-out tokens (
no-auto-routing,manual-only,skip-browser-debug) force manual path. - Keep
Core modedefault unless strict reproducibility is explicitly required. - If capability gate falls back, continue in
terminal-probeand avoid page-sidefetch(debugEndpoint)calls.
Always run guarded bootstrap first:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/bootstrap_guarded.py" --project-root <project-root> --jsonRun again with actual app URL (required for browser-fetch mode):
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/bootstrap_guarded.py" --project-root <project-root> --actual-app-url <url> --jsonOptional visual starter helper:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/visual_debug_start.py" --project-root <project-root> --actual-app-url <url> --jsonFor drag/parity-oriented baseline capture without custom scenarios:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/visual_debug_start.py" --project-root <project-root> --actual-app-url <url> --scenario-profile drag-parity --jsonFor bounded recovery + headed parity evidence in one run:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/visual_debug_start.py" --project-root <project-root> --actual-app-url <url> --auto-recover-session --headed-evidence --reference-image /path/ref.png --evidence-label baseline --jsonOptional session matching control:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/visual_debug_start.py" --project-root <project-root> --actual-app-url <url> --tab-url-match-strategy origin-path --jsonExit code contract: returns non-zero when guarded bootstrap fails, strict readiness gate remains false (readyForScenarioRun=false outside plan mode), headed-evidence fails, or terminal-probe capture is executed and fails.
JSON output includes:
modeSelection(selectedMode,executionMode,reason,alternateMode,alternateModeRationale)bootstrapConfigChanges(appliedRecommendations,recommendedDiffDigest)readinessVerdict(status,modeHint,reasons,summary,nextAction)recoveryLane(class,reason, orderedactions,primaryAction)terminalProbeNextAction(mirrors terminal-probenextActionwhen capture reports a deterministic recovery command)
If Enhanced prerequisites are unavailable, continue in Core mode from README.md.
Branch from machine-readable verdict:
- Browser instrumentation is allowed only when
browserInstrumentation.canInstrumentFromBrowser = true. - If
falseorbootstrap.status = fallback, mode isterminal-probe. - In
terminal-probe, do not add page-sidefetch(debugEndpoint)instrumentation. - Require
readyForScenarioRun = truebefore scenario execution; iffalse, treat launch as blocked and usereadinessReasonsfor remediation. - In
browser-fetch,checks.headedEvidence.ok=falsecontributesheaded-evidence:*readiness reasons and blocks strict launch.
Use checks.appUrl diagnostics as a mini-checklist:
checks.appUrl.checklistfor pass/fail steps.checks.appUrl.recommendedCommands(object entries) andchecks.appUrl.recommendedCommandsText(command strings) for re-run and optional auto-fix commands.checks.appUrl.canAutoFix+checks.appUrl.autoFixModeto confirm that auto-fix is explicit-flag only.checks.appUrl.matchType(exact/loopback-equivalent) andchecks.appUrl.nextActionfor deterministic next step selection.checks.appUrl.primaryRecommendedCommandis the copy-ready remediation command.- Always print
checks.appUrl.configAppUrlandchecks.appUrl.actualAppUrltogether in run status. - If
checks.appUrl.statusisnot-providedormismatch, run the first recommended command before continuing.
Fallback cause diagnostics are explicit:
browserInstrumentation.failureCategorybrowserInstrumentation.failedChecksbrowserInstrumentation.reason
Headless false-negative guard is explicit:
checks.headedEvidencechecks.warnings
Playwright compatibility diagnostics are also machine-readable:
checks.tools.playwright.wrapperSmokechecks.tools.playwright.npxSmokechecks.tools.playwright.selectedCommandchecks.tools.playwright.selectedBinarychecks.tools.playwright.functionalSmoke(can beskipped=truewhennpxis unavailable; this does not block a healthy wrapper probe)
HTTP:
curl "http://127.0.0.1:4678/events/query?from=2026-02-06T12:00:00.000Z&to=2026-02-06T12:30:00.000Z&tag=checkout-submit&limit=500"CLI:
npm run agent:query -- --from 2026-02-06T12:00:00.000Z --to 2026-02-06T12:30:00.000Z --tag checkout-submitCross-project feedback triage (structured signals + backlog slice):
npm run agent:feedback -- --window 24h --targets browser-debug,fix-app-bugs --jsonCorrelation strategy:
- Primary key:
traceId - Secondary:
tag - Final filter: reproduction time window (
from/to)
- In target project, update
.codex/browser-debug.jsonwith project URL and ports. - For local dev, keep both
localhostand127.0.0.1incapture.allowedDomains. - Run guarded skill bootstrap:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/bootstrap_guarded.py" --project-root <project-root> --json- Re-run with the real page URL:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/bootstrap_guarded.py" --project-root <project-root> --actual-app-url <url> --jsonIf checks.appUrl.status = not-provided or checks.appUrl.status = mismatch, run:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/bootstrap_guarded.py" --project-root <project-root> --actual-app-url <url> --apply-recommended --json- If guarded bootstrap reports
bootstrap.status = ok, runtime config is managed through the underlying bootstrap. - If guarded bootstrap reports
bootstrap.status = fallback, continue in terminal-probe mode. - Extension auto-discovers core port (
4678..4698), fetches runtime config, and hot-updates capture rules when core API is reachable.
When running terminal-probe scenario capture/metrics:
python3 "$CODEX_HOME/skills/fix-app-bugs/scripts/terminal_probe_pipeline.py" --project-root <project-root> --session-id auto --tab-url <url> --scenarios "$CODEX_HOME/skills/fix-app-bugs/references/terminal-probe-scenarios.example.json" --jsonOptional reliability flags:
--tab-url-match-strategy origin-pathfor query/hash-tolerant auto-session resolution with exact retry on unique CDP match.--force-new-sessionto stop an active session beforesession/ensure.--open-tab-if-missingto call CDPjson/newonTARGET_NOT_FOUNDand retrysession/ensure(enabled by default in auto mode).--no-open-tab-if-missingto disable automatic tab-open recovery in auto mode.--resize-interpolation nearest|bilinearto control reference resize interpolation.--no-normalize-reference-sizeto disable strict->resize fallback for dimension mismatch.visual_debug_start.py --auto-recover-sessionto run one bounded/health -> /session/stop -> /session/ensurerecovery attempt before re-running bootstrap.visual_debug_start.py --headed-evidenceto produce headed evidence bundle (--reference-imagerequired inbrowser-fetch; terminal-probe reuses existing bundle paths).
Recovery precedence (deterministic):
app-url-gate:*-> config alignment (preview -> apply -> resume).session-state:*orcdp-unavailable:*-> session/CDP lane (soft recovery -> force-new-session -> open-tab-if-missing).- If still blocked, stop scenario launch and inspect
readinessReasons+recoveryLanebefore retrying.
Customize the scenario file with real ON/OFF/paused selectors for your app.
Or resolve/reuse session directly from CLI:
npm run agent:session -- --tab-url <url>- Reload:
npm run agent:cmd -- --do reload- Wait:
npm run agent:cmd -- --do wait --ms 1200- Navigate:
npm run agent:cmd -- --do navigate --url "http://127.0.0.1:5173/"- Evaluate JS on page:
npm run agent:cmd -- --do evaluate --expr "window.location.href"- Click:
npm run agent:cmd -- --session <id> --do click --selector "button[data-test=save]"- Type:
npm run agent:cmd -- --session <id> --do type --selector "input[name=email]" --text "[email protected]" --clear- Snapshot:
npm run agent:cmd -- --session <id> --do snapshot --fullPage- Compare reference images:
npm run agent:cmd -- --session <id> --do compare-reference --actual /path/app.png --reference /path/ref.png --label baseline --dimension-policy strict --resize-interpolation bilinear- Parity bundle helper:
npm run agent:parity-bundle -- --session <id> --reference /path/ref.png --label baseline- WebGL diagnostics:
npm run agent:cmd -- --session <id> --do webgl-diagnosticsNotes:
--session <id>is optional for/command; when omitted, runtime uses active session if available.- For
compare-reference, command can run without active CDP session and without explicitsessionId. - Session ensure/start support
matchStrategy(exact|origin-path|origin, defaultexact).
- Logs and screenshot artifacts are stored under
logs/browser-debug. - Hourly cleanup removes entries older than 7 days.
After bugfix work, run guarded cleanup:
bash "$CODEX_HOME/skills/fix-app-bugs/scripts/cleanup_guarded.sh" .Strict mode:
bash "$CODEX_HOME/skills/fix-app-bugs/scripts/cleanup_guarded.sh" . --strictStrict mode scans runtime code paths only (for example src, app, server, test, tests, packages/*/src) and ignores documentation-only markers in markdown feedback files.
If check_instrumentation_cleanup.sh is missing, guarded cleanup automatically falls back to:
rg -n "BUGFIX_TRACE|debugEndpoint|traceId|issue tag" src testFallback scan uses the same runtime target selection when available.
For WebGL/render bugs, do not treat a black headless screenshot as the only evidence of regression or fix success. Confirm with browser-visible behavior or concrete runtime errors. At least one headed validation run is required for final success claims.
For parity-sensitive work, keep one artifact folder containing:
runtime.jsonmetrics.jsonsummary.jsonactual.pngreference.pngdiff.png(when enabled)notes.md
Default artifact path:
logs/browser-debug/<sessionId>/artifacts/<runId>/...
Terminal-probe pipeline artifact path (default):
logs/browser-debug/<sessionId>/terminal-probe/<timestamp>/...
Use a lightweight report for iterative tuning loops:
Hypothesis deltaEvidence deltaNext step
Template path:
skills/fix-app-bugs/references/interim-visual-report-template.md
Keep the five-block report as final-closure-only in Enhanced mode.
If the same scenario fails parity for 3 consecutive cycles or 90 minutes with no meaningful metrics improvement:
- Stop tuning.
- Record interim evidence bundle paths.
- Convert the effort into rollback + retrospective planning.
Local skill source of truth:
$CODEX_HOME/skills/fix-app-bugs (fallback: $HOME/.codex/skills/fix-app-bugs)
Mirror location in this repo:
skills/fix-app-bugs
Workflow:
npm run skill:sync:from-localnpm run skill:sync:check- Commit/push
Every fix-app-bugs run should end with these five blocks:
Root CausePatchValidationInstrumentation StatusResidual Risk
If Browser Debug bootstrap was unavailable, state it explicitly in Validation.