← Codex Browser RecorderCONTENT HISTORY

Update to Codex Browser Recorder

Snapshot Sep 30, 2026 · 23:13 UTC · version 0.4.0

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "name": "record-browser",
  "description": "Check setup or record one explicitly approved Codex In-app Browser flow as a private local MP4; pointer flows add a visible cursor and click feedback. Use only when the user explicitly invokes $codex-browser-recorder:record-browser.",
  "included_files": [
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 304
    },
    {
      "relative_path": "assets/codex-style-click-ring.xpm",
      "size_in_bytes": 3459
    },
    {
      "relative_path": "assets/codex-style-cursor.xpm",
      "size_in_bytes": 1006
    },
    {
      "relative_path": "scripts/browser-recording.mjs",
      "size_in_bytes": 20925
    },
    {
      "relative_path": "scripts/cdp-event-batch.mjs",
      "size_in_bytes": 594
    },
    {
      "relative_path": "scripts/create-recording.mjs",
      "size_in_bytes": 34299
    },
    {
      "relative_path": "scripts/cursor-recording.mjs",
      "size_in_bytes": 33456
    },
    {
      "relative_path": "scripts/doctor.mjs",
      "size_in_bytes": 6041
    },
    {
      "relative_path": "scripts/media-recorder.mjs",
      "size_in_bytes": 13714
    },
    {
      "relative_path": "scripts/record-browser-flow.mjs",
      "size_in_bytes": 17805
    },
    {
      "relative_path": "scripts/recording-artifacts.mjs",
      "size_in_bytes": 13334
    },
    {
      "relative_path": "scripts/recording-outcome.mjs",
      "size_in_bytes": 10274
    },
    {
      "relative_path": "scripts/recording-policy.mjs",
      "size_in_bytes": 2636
    },
    {
      "relative_path": "scripts/validate-video.mjs",
      "size_in_bytes": 5359
    }
  ],
  "skill_md_contents": "---\nname: record-browser\ndescription: Check setup or record one explicitly approved Codex In-app Browser flow as a private local MP4; pointer flows add a visible cursor and click feedback. Use only when the user explicitly invokes $codex-browser-recorder:record-browser.\n---\n\n# Record Browser\n\n## Build A Local Plan\n\nCollect the request without Browser activity:\n\n- Set `preflightOnly` only for an explicit doctor, diagnose, check, or preflight request.\n- For recording, require an HTTPS or approved loopback target plus either one or more concrete actions or an explicit passive duration.\n- Treat the normalized target site as the approved origin for the whole recording.\n- Set `durationWasExplicit` from the user's words. Use 15 seconds when omitted, but end after the last action and any bounded pointer-feedback tail. Require an explicit 5–60 second duration for passive or wait-only recording.\n- Set `recordingMode` to `interactive` by default. Use `unattended` only when the user explicitly requests an unattended, headless-style, background-start, or automated E2E QA recording. Both modes use the Codex In-app Browser; do not describe Unattended Recording as a separate headless Chromium surface.\n- Classify every action as `pointer`, `keyboard`, or `programmatic`. Pointer includes click, hover, drag, and pointer-positioned scroll.\n- Accept an optional absolute destination and privacy-safe recording name. Otherwise use `~/Downloads/Codex Browser Recordings/` and a timestamp name.\n\nBrowser Recorder is content-neutral. Do not classify page content, redact visible\nfields, or refuse an otherwise valid request based on authentication, privacy,\nor sensitivity. It does not protect, mask, manage, or authenticate credentials\nor sensitive content; anything visible in the approved viewport may appear in\nthe video.\n\nResolve the installed skill directory from the catalog entry that loaded this file. Never guess a cache path or use a source checkout. Import `checkSetup`, `prepareRecording`, and `recordApproved` from `scripts/record-browser-flow.mjs` in that exact directory with `pathToFileURL` in the persistent Node runtime.\n\nDefine each action before preparation. Its `perform({ tab })` function must contain exactly the approved Browser call. Labels must describe the approved action generically; do not copy page text, form values, or full URLs into consent or diagnostics.\n\n```js\nconst plannedActions = [\n  // {\n  //   label: \"Open the pricing section\",\n  //   modality: \"pointer\",\n  //   perform: ({ tab }) => tab.<exact approved Browser call>,\n  // },\n];\n\nconst preparation = await prepareRecording({\n  actions: plannedActions,\n  destinationDirectory,\n  durationMs,\n  durationWasExplicit,\n  now: new Date(),\n  preflightOnly,\n  recordingMode,\n  recordingName,\n  targetUrl,\n  temporaryRoot,\n});\n```\n\n`prepareRecording()` performs pure request validation plus local FFmpeg/FFprobe and destination checks. It must not create, navigate, or acquire a Browser tab or CDP capability. Treat the returned preparation as opaque: do not clone, spread, reconstruct, or mutate it.\n\nTechnical target restrictions remain content-independent: malformed URLs,\nprohibited URL credentials, unsupported schemes, an unapproved origin, an\ninvalid duration, capture or encoding failure, media validation failure, and\nincomplete cleanup remain deterministic Technical Blockers or terminal\nfailures.\n\nIf `status` is `blocked`, report every Technical Blocker in order using only its `code`, `summary`, and `remediation`, then stop. For `preflight_prepared`, continue only with the explicit setup-check path below. For `prepared`, continue to consent. Do not expose raw booleans.\n\n## Complete The Setup Check\n\nFor `status: \"preflight_prepared\"`, follow the installed Browser control skill. Resolve its installed plugin root from its catalog entry, and pass one bounded Codex In-app Browser acquisition callback to the Recording Flow:\n\n```js\nconst acquireBrowser = async () => {\n  if (globalThis.agent?.browsers == null) {\n    const { setupBrowserRuntime } =\n      await import(\"<Browser plugin root>/scripts/browser-client.mjs\");\n    await setupBrowserRuntime({ globals: globalThis });\n  }\n  if (globalThis.iab == null) {\n    globalThis.iab = await agent.browsers.get(\"iab\");\n    nodeRepl.write(await iab.documentation());\n  }\n  return globalThis.iab;\n};\n\nconst setupOutcome = await checkSetup(preparation, {\n  acquireBrowser,\n  signal,\n});\n```\n\nDo not use Chrome, `getForUrl`, `getDefault`, an existing arbitrary tab, or any fallback Recording Surface. The Recording Flow owns the bounded Browser acquisition, one fresh diagnostic tab when needed, full-CDP capability probe, and verified exact-tab cleanup. It consumes the setup preparation exactly once. Do not call lower-level tab creation or capability APIs directly.\n\nThe setup check must not navigate to a requested recording site, start a Recording Session, create an MP4 or raw frame dump, or upload anything.\n\nIf `status` is `blocked`, report every Technical Blocker in order using only its `code`, `summary`, and `remediation`, then stop. For `preflight_passed`, lead with `Local recording preflight passed`, report the planned destination, and state that the local media toolchain, destination, Codex In-app Browser, and full CDP access checks passed. Do not expose raw booleans. Stop after this setup result; do not request recording consent or start a recording.\n\n## Obtain One Consent\n\nFor `status: \"prepared\"`, present one compact confirmation before any Browser activity:\n\n- **What:** the approved site, concrete actions, and when the recording will end;\n- **Mode:** whether this is the default Interactive Recording, which shows the Browser before navigation, or an explicitly requested Unattended Recording, which begins and remains hidden;\n- **Where:** the exact local filename and folder; the MP4 has no audio and is not uploaded;\n- **What is visible:** the full page viewport, including visible embedded frames, plus cursor and click feedback for pointer actions; browser controls and other tabs are excluded;\n- **Content Warning:** the complete approved page viewport may include private, authenticated, or sensitive content. This warning is non-blocking; continue only if the user confirms they are authorized to record it and will handle the local file appropriately.\n\nExplain that macOS may request folder access and that verification failure means\nno final video is saved. Continue only after explicit confirmation. Treat user\ndenial as declined authorization with no Browser activity; it is neither a\nplatform rejection nor a Technical Blocker.\n\n## Record The Approved Plan\n\nAfter consent, follow the installed Browser control skill. Resolve its installed plugin root from its catalog entry, initialize `browser-client.mjs` once, and emit the Codex In-app Browser documentation once. Acquire only the Codex In-app Browser:\n\n```js\nif (globalThis.agent?.browsers == null) {\n  const { setupBrowserRuntime } =\n    await import(\"<Browser plugin root>/scripts/browser-client.mjs\");\n  await setupBrowserRuntime({ globals: globalThis });\n}\nif (globalThis.iab == null) {\n  globalThis.iab = await agent.browsers.get(\"iab\");\n  nodeRepl.write(await iab.documentation());\n}\nconst selectedBrowser = globalThis.iab;\n```\n\nDo not use Chrome, `getForUrl`, `getDefault`, an existing arbitrary tab, or any fallback Recording Surface.\n\nAfter user authorization, a Codex or Browser permission denial is a platform\nrejection. Report the returned cancellation or rejection without relabeling it\nas user denial or a Technical Blocker, and never retry or bypass the rejected\napproval.\n\nCall `recordApproved()` once with the exact opaque preparation and selected Browser:\n\n```js\nconst outcome = await recordApproved(preparation, {\n  browser: selectedBrowser,\n  signal,\n});\n```\n\nThe Recording Flow owns the fresh tab, navigation, CDP acquisition, first-frame gate, origin enforcement, per-action pointer evidence, duration, media validation, publication, rollback, verified exact-tab cleanup, and singleton release. It consumes the preparation exactly once and returns one terminal outcome. Do not call lower-level recording modules, perform extra actions, retry approval, broaden the origin, enable Developer mode, install packages, or switch the Browser. Never switch to another Recording Surface.\n\nThe Recording Flow establishes and verifies the approved visibility mode before\nnavigation. Never silently fall back between Interactive Recording and\nUnattended Recording.\n\n## Report The Terminal Outcome\n\nFor `completed`, require `outcome.result.status === \"passed\"`. Lead with `Recording completed`, then report duration, dimensions, and `MP4 video (H.264, no audio)`. For a pointer plan, also report the visible project cursor and click feedback. For a plan with no pointer action, do not claim that a cursor is visible. Then provide `[Saved video](<absolute output path>)` plus the same plain absolute path. Offer `Open in Finder`; do not open or play it without a request.\n\nOffer bounded capture counters only as diagnostics after the product result.\n\nFor `failed` or `cancelled`, report only `outcome.failure.code`, `.summary`, and `.remediation`. Never expose URLs, page text, raw frames, CDP payloads, FFmpeg stderr, credentials, or internal plugin paths.\n\nReport bounded cleanup state after the primary result:\n\n- `cleanup.directory`: `Cleanup incomplete; delete locally: <path>`. For `saved_recording_persistence_failed`, instead identify it as a temporary unfinished video to copy before deletion.\n- `cleanup.file`: `Cleanup incomplete; delete local file: <path>`.\n- `artifactCleanupIncomplete` without a directory: inspect the operating-system temporary directory for a `codex-browser-recorder-` entry.\n- `browserTabCleanupIncomplete`: close the fresh recording tab manually without reporting its URL.\n- `resourceCleanupIncomplete`: quit Codex before retrying if recording activity continues.\n\nNever convert a failed outcome into success or publish a failed recording.\n"
}

SHA-256: 7607186abb6e643df6b24ce4b6dff3bd03fed65369febac0645f20d600b324fb