{"id":"7c160116-bd75-46bf-ab36-214b9077f502","entityType":"agent","slug":"clawhub-tridefender-playwright-interactive","name":"Playwright Interactive","canonicalUrl":"https://www.xpersona.co/agent/clawhub-tridefender-playwright-interactive","canonicalPath":"/agent/clawhub-tridefender-playwright-interactive","generatedAt":"2026-10-12T19:33:23.484Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T22:54:16.154Z","emptyReason":null},"description":"Persistent browser and Electron QA Skill: Playwright Interactive Owner: tridefender Summary: Persistent browser and Electron QA Tags: latest:1.0.0 Version history: v1.0.0 | 2026-04-18T21:36:08.042Z | auto Initial release: Adds persistent Playwright + Electron browser interaction through js_repl for rapid, iterative UI debugging. - Supports persistent Playwright sessions with shared browser handles—avoids repeated launching, improving iteration speed.","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 981 downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s1785z67w6q9dwydts4xxxr0fs852myz:playwright-interactive","sourceUrl":"https://clawhub.ai/tridefender/playwright-interactive","homepage":"https://clawhub.ai/tridefender/skills/playwright-interactive","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/tridefender/playwright-interactive","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/tridefender/skills/playwright-interactive","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Persistent browser and Electron QA Skill: Playwright Interactive Owner: tridefender Summary: Persistent browser and Electron QA Tags: latest:1.0.0 Version histo"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T22:54:16.154Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T22:54:16.154Z","emptyReason":null},"stars":null,"forks":null,"downloads":981,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"1.0.0","tractionLabel":"981 downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T22:54:16.073Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T22:54:16.154Z","lastCrawledAt":"2026-10-11T22:54:16.073Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T22:54:16.073Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.0","createdAt":"2026-04-18T21:36:08.042Z","changelog":"Initial release: Adds persistent Playwright + Electron browser interaction through js_repl for rapid, iterative UI debugging. - Supports persistent Playwright sessions with shared browser handles—avoids repeated launching, improving iteration speed. - Enables functional and visual QA for both web and Electron apps via js_repl interface. - Documents setup, workflow best practices, and common scenarios for session and context management. - Provides sample bootstrap, web, and mobile context management scripts with clear recovery steps. - Details explicit viewport and native-window session choices for comprehensive QA coverage.","fileCount":7,"zipByteSize":17560}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s1785z67w6q9dwydts4xxxr0fs852myz:playwright-interactive","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-12T19:33:23.484Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tridefender-playwright-interactive/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T22:54:16.154Z","emptyReason":null},"readme":"Skill: Playwright Interactive\n\nOwner: tridefender\n\nSummary: Persistent browser and Electron QA\n\nTags: latest:1.0.0\n\nVersion history:\n\nv1.0.0 | 2026-04-18T21:36:08.042Z | auto\n\nInitial release: Adds persistent Playwright + Electron browser interaction through js_repl for rapid, iterative UI debugging.\n\n- Supports persistent Playwright sessions with shared browser handles—avoids repeated launching, improving iteration speed.\n- Enables functional and visual QA for both web and Electron apps via js_repl interface.\n- Documents setup, workflow best practices, and common scenarios for session and context management.\n- Provides sample bootstrap, web, and mobile context management scripts with clear recovery steps.\n- Details explicit viewport and native-window session choices for comprehensive QA coverage.\n\nArchive index:\n\nArchive v1.0.0: 7 files, 17560 bytes\n\nFiles: agents/openai.yaml (345b), assets/playwright-small.svg (843b), LICENSE.txt (11552b), NOTICE.txt (478b), skill-card.md (2073b), SKILL.md (31711b), _meta.json (141b)\n\nFile v1.0.0:SKILL.md\n\n---\nname: \"playwright-interactive\"\ndescription: \"Persistent browser and Electron interaction through `js_repl` for fast iterative UI debugging.\"\n---\n\n# Playwright Interactive Skill\n\nUse a persistent `js_repl` Playwright session to debug local web or Electron apps, keep the same handles alive across iterations, and run functional plus visual QA without restarting the whole toolchain unless the process ownership changed.\n\n## Preconditions\n\n- `js_repl` must be enabled for this skill.\n- If `js_repl` is missing, enable it in `~/.codex/config.toml`:\n\n```toml\n[features]\njs_repl = true\n```\n\n- You can also start a new session with `--enable js_repl` (equivalent to `-c features.js_repl=true`).\n- After enabling `js_repl`, start a new Codex session so the tool list refreshes.\n- For now, run this workflow with sandboxing disabled: start Codex with `--sandbox danger-full-access` (or the equivalent config for `sandbox_mode=danger-full-access`). This is a temporary requirement while `js_repl` + Playwright support inside the sandbox is still being completed.\n- Run setup from the same project directory you need to debug.\n- Treat `js_repl_reset` as a recovery tool, not routine cleanup. Resetting the kernel destroys your Playwright handles.\n\n## One-time setup\n\n```bash\ntest -f package.json || npm init -y\nnpm install playwright\n# Web-only, for headed Chromium or mobile emulation:\n# npx playwright install chromium\n# Electron-only, and only if the target workspace is the app itself:\n# npm install --save-dev electron\nnode -e \"import('playwright').then(() => console.log('playwright import ok')).catch((error) => { console.error(error); process.exit(1); })\"\n```\n\nIf you switch to a different workspace later, repeat setup there.\n\n## Core Workflow\n\n1. Write a brief QA inventory before testing:\n   - Build the inventory from three sources: the user's requested requirements, the user-visible features or behaviors you actually implemented, and the claims you expect to make in the final response.\n   - Anything that appears in any of those three sources must map to at least one QA check before signoff.\n   - List the user-visible claims you intend to sign off on.\n   - List every meaningful user-facing control, mode switch, or implemented interactive behavior.\n   - List the state changes or view changes each control or implemented behavior can cause.\n   - Use this as the shared coverage list for both functional QA and visual QA.\n   - For each claim or control-state pair, note the intended functional check, the specific state where the visual check must happen, and the evidence you expect to capture.\n   - If a requirement is visually central but subjective, convert it into an observable QA check instead of leaving it implicit.\n   - Add at least 2 exploratory or off-happy-path scenarios that could expose fragile behavior.\n2. Run the bootstrap cell once.\n3. Start or confirm any required dev server in a persistent TTY session.\n4. Launch the correct runtime and keep reusing the same Playwright handles.\n5. After each code change, reload for renderer-only changes or relaunch for main-process/startup changes.\n6. Run functional QA with normal user input.\n7. Run a separate visual QA pass.\n8. Verify viewport fit and capture the screenshots needed to support your claims.\n9. Clean up the Playwright session only when the task is actually finished.\n\n## Bootstrap (Run Once)\n\n```javascript\nvar chromium;\nvar electronLauncher;\nvar browser;\nvar context;\nvar page;\nvar mobileContext;\nvar mobilePage;\nvar electronApp;\nvar appWindow;\n\ntry {\n  ({ chromium, _electron: electronLauncher } = await import(\"playwright\"));\n  console.log(\"Playwright loaded\");\n} catch (error) {\n  throw new Error(\n    `Could not load playwright from the current js_repl cwd. Run the setup commands from this workspace first. Original error: ${error}`\n  );\n}\n```\n\nBinding rules:\n\n- Use `var` for the shared top-level Playwright handles because later `js_repl` cells reuse them.\n- The setup cells below are intentionally short happy paths. If a handle looks stale, set that binding to `undefined` and rerun the cell instead of adding recovery logic everywhere.\n- Prefer one named handle per surface you care about (`page`, `mobilePage`, `appWindow`) over repeatedly rediscovering pages from the context.\n\nShared web helpers:\n\n```javascript\nvar resetWebHandles = function () {\n  context = undefined;\n  page = undefined;\n  mobileContext = undefined;\n  mobilePage = undefined;\n};\n\nvar ensureWebBrowser = async function () {\n  if (browser && !browser.isConnected()) {\n    browser = undefined;\n    resetWebHandles();\n  }\n\n  browser ??= await chromium.launch({ headless: false });\n  return browser;\n};\n\nvar reloadWebContexts = async function () {\n  for (const currentContext of [context, mobileContext]) {\n    if (!currentContext) continue;\n    for (const p of currentContext.pages()) {\n      await p.reload({ waitUntil: \"domcontentloaded\" });\n    }\n  }\n  console.log(\"Reloaded existing web tabs\");\n};\n```\n\n## Choose Session Mode\n\nFor web apps, use an explicit viewport by default and treat native-window mode as a separate validation pass.\n\n- Use an explicit viewport for routine iteration, breakpoint checks, reproducible screenshots, snapshot diffs, and model-assisted localization. This is the default because it is stable across machines and avoids host window-manager variability.\n- When you need deterministic high-DPI behavior, keep the explicit viewport and add `deviceScaleFactor` rather than switching straight to native-window mode.\n- Use native-window mode (`viewport: null`) for a separate headed pass when you need to validate launched window size, OS-level DPI behavior, browser chrome interactions, or bugs that may depend on the host display configuration.\n- For Electron, assume native-window behavior all the time. Electron launches through Playwright with `noDefaultViewport`, so treat it like a real desktop window and check the as-launched size and layout before resizing anything.\n- When signoff depends on both layout breakpoints and real desktop behavior, do both passes: explicit viewport first for deterministic QA, then native-window validation for final environment-specific checks.\n- Treat switching modes as a context reset. Do not reuse a viewport-emulated `context` for a native-window pass or vice versa; close the old `page` and `context`, then create a new one for the new mode.\n\n## Start or Reuse Web Session\n\nDesktop and mobile web sessions share the same `browser`, helpers, and QA flow. The main difference is which context and page pair you create.\n\n### Desktop Web Context\n\nSet `TARGET_URL` to the app you are debugging. For local servers, prefer `127.0.0.1` over `localhost`.\n\n```javascript\nvar TARGET_URL = \"http://127.0.0.1:3000\";\n\nif (page?.isClosed()) page = undefined;\n\nawait ensureWebBrowser();\ncontext ??= await browser.newContext({\n  viewport: { width: 1600, height: 900 },\n});\npage ??= await context.newPage();\n\nawait page.goto(TARGET_URL, { waitUntil: \"domcontentloaded\" });\nconsole.log(\"Loaded:\", await page.title());\n```\n\nIf `context` or `page` is stale, set `context = page = undefined` and rerun the cell.\n\n### Mobile Web Context\n\nReuse `TARGET_URL` when it already exists; otherwise set a mobile target directly.\n\n```javascript\nvar MOBILE_TARGET_URL = typeof TARGET_URL === \"string\"\n  ? TARGET_URL\n  : \"http://127.0.0.1:3000\";\n\nif (mobilePage?.isClosed()) mobilePage = undefined;\n\nawait ensureWebBrowser();\nmobileContext ??= await browser.newContext({\n  viewport: { width: 390, height: 844 },\n  isMobile: true,\n  hasTouch: true,\n});\nmobilePage ??= await mobileContext.newPage();\n\nawait mobilePage.goto(MOBILE_TARGET_URL, { waitUntil: \"domcontentloaded\" });\nconsole.log(\"Loaded mobile:\", await mobilePage.title());\n```\n\nIf `mobileContext` or `mobilePage` is stale, set `mobileContext = mobilePage = undefined` and rerun the cell.\n\n### Native-Window Web Pass\n\n```javascript\nvar TARGET_URL = \"http://127.0.0.1:3000\";\n\nawait ensureWebBrowser();\n\nawait page?.close().catch(() => {});\nawait context?.close().catch(() => {});\npage = undefined;\ncontext = undefined;\n\nbrowser ??= await chromium.launch({ headless: false });\ncontext = await browser.newContext({ viewport: null });\npage = await context.newPage();\n\nawait page.goto(TARGET_URL, { waitUntil: \"domcontentloaded\" });\nconsole.log(\"Loaded native window:\", await page.title());\n```\n\n## Start or Reuse Electron Session\n\nSet `ELECTRON_ENTRY` to `.` when the current workspace is the Electron app and `package.json` points `main` to the right entry file. If you need to target a specific main-process file directly, use a path such as `./main.js` instead.\n\n```javascript\nvar ELECTRON_ENTRY = \".\";\n\nif (appWindow?.isClosed()) appWindow = undefined;\n\nif (!appWindow && electronApp) {\n  await electronApp.close().catch(() => {});\n  electronApp = undefined;\n}\n\nelectronApp ??= await electronLauncher.launch({\n  args: [ELECTRON_ENTRY],\n});\n\nappWindow ??= await electronApp.firstWindow();\n\nconsole.log(\"Loaded Electron window:\", await appWindow.title());\n```\n\nIf `js_repl` is not already running from the Electron app workspace, pass `cwd` explicitly when launching.\n\nIf the app process looks stale, set `electronApp = appWindow = undefined` and rerun the cell.\n\nIf you already have an Electron session but need a fresh process after a main-process, preload, or startup change, use the restart cell in the next section instead of rerunning this one.\n\n## Reuse Sessions During Iteration\n\nKeep the same session alive whenever you can.\n\nWeb renderer reload:\n\n```javascript\nawait reloadWebContexts();\n```\n\nElectron renderer-only reload:\n\n```javascript\nawait appWindow.reload({ waitUntil: \"domcontentloaded\" });\nconsole.log(\"Reloaded Electron window\");\n```\n\nElectron restart after main-process, preload, or startup changes:\n\n```javascript\nawait electronApp.close().catch(() => {});\nelectronApp = undefined;\nappWindow = undefined;\n\nelectronApp = await electronLauncher.launch({\n  args: [ELECTRON_ENTRY],\n});\n\nappWindow = await electronApp.firstWindow();\nconsole.log(\"Relaunched Electron window:\", await appWindow.title());\n```\n\nIf your launch requires an explicit `cwd`, include the same `cwd` here.\n\nDefault posture:\n\n- Keep each `js_repl` cell short and focused on one interaction burst.\n- Reuse the existing top-level bindings (`browser`, `context`, `page`, `electronApp`, `appWindow`) instead of redeclaring them.\n- If you need isolation, create a new page or a new context inside the same browser.\n- For Electron, use `electronApp.evaluate(...)` only for main-process inspection or purpose-built diagnostics.\n- Fix helper mistakes in place; do not reset the REPL unless the kernel is actually broken.\n\n## Checklists\n\n### Session Loop\n\n- Bootstrap `js_repl` once, then keep the same Playwright handles alive across iterations.\n- Launch the target runtime from the current workspace.\n- Make the code change.\n- Reload or relaunch using the correct path for that change.\n- Update the shared QA inventory if exploration reveals an additional control, state, or visible claim.\n- Re-run functional QA.\n- Re-run visual QA.\n- Capture final artifacts only after the current state is the one you are evaluating.\n\n### Reload Decision\n\n- Renderer-only change: reload the existing page or Electron window.\n- Main-process, preload, or startup change: relaunch Electron.\n- New uncertainty about process ownership or startup code: relaunch instead of guessing.\n\n### Functional QA\n\n- Use real user controls for signoff: keyboard, mouse, click, touch, or equivalent Playwright input APIs.\n- Verify at least one end-to-end critical flow.\n- Confirm the visible result of that flow, not just internal state.\n- For realtime or animation-heavy apps, verify behavior under actual interaction timing.\n- Work through the shared QA inventory rather than ad hoc spot checks.\n- Cover every obvious visible control at least once before signoff, not only the main happy path.\n- For reversible controls or stateful toggles in the inventory, test the full cycle: initial state, changed state, and return to the initial state.\n- After the scripted checks pass, do a short exploratory pass using normal input for 30-90 seconds instead of following only the intended path.\n- If the exploratory pass reveals a new state, control, or claim, add it to the shared QA inventory and cover it before signoff.\n- `page.evaluate(...)` and `electronApp.evaluate(...)` may inspect or stage state, but they do not count as signoff input.\n\n### Visual QA\n\n- Treat visual QA as separate from functional QA.\n- Use the same shared QA inventory defined before testing and updated during QA; do not start visual coverage from a different implicit list.\n- Restate the user-visible claims and verify each one explicitly; do not assume a functional pass proves a visual claim.\n- A user-visible claim is not signed off until it has been inspected in the specific state where it is meant to be perceived.\n- Inspect the initial viewport before scrolling.\n- Confirm that the initial view visibly supports the interface's primary claims; if a core promised element is not clearly perceptible there, treat that as a bug.\n- Inspect all required visible regions, not just the main interaction surface.\n- Inspect the states and modes already enumerated in the shared QA inventory, including at least one meaningful post-interaction state when the task is interactive.\n- If motion or transitions are part of the experience, inspect at least one in-transition state in addition to the settled endpoints.\n- If labels, overlays, annotations, guides, or highlights are meant to track changing content, verify that relationship after the relevant state change.\n- For dynamic or interaction-dependent visuals, inspect long enough to judge stability, layering, and readability; do not rely on a single screenshot for signoff.\n- For interfaces that can become denser after loading or interaction, inspect the densest realistic state you can reach during QA, not only the empty, loading, or collapsed state.\n- If the product has a defined minimum supported viewport or window size, run a separate visual QA pass there; otherwise, choose a smaller but still realistic size and inspect it explicitly.\n- Distinguish presence from implementation: if an intended affordance is technically there but not clearly perceptible because of weak contrast, occlusion, clipping, or instability, treat that as a visual failure.\n- If any required visible region is clipped, cut off, obscured, or pushed outside the viewport in the state you are evaluating, treat that as a bug even if page-level scroll metrics appear acceptable.\n- Look for clipping, overflow, distortion, layout imbalance, inconsistent spacing, alignment problems, illegible text, weak contrast, broken layering, and awkward motion states.\n- Judge aesthetic quality as well as correctness. The UI should feel intentional, coherent, and visually pleasing for the task.\n- Prefer viewport screenshots for signoff. Use full-page captures only as secondary debugging artifacts, and capture a focused screenshot when a region needs closer inspection.\n- If motion makes a screenshot ambiguous, wait briefly for the UI to settle, then capture the image you are actually evaluating.\n- Before signoff, explicitly ask: what visible part of this interface have I not yet inspected closely?\n- Before signoff, explicitly ask: what visible defect would most likely embarrass this result if the user looked closely?\n\n### Signoff\n\n- The functional path passed with normal user input.\n- Coverage is explicit against the shared QA inventory: note which requirements, implemented features, controls, states, and claims were exercised, and call out any intentional exclusions.\n- The visual QA pass covered the whole relevant interface.\n- Each user-visible claim has a matching visual check and reviewed screenshot artifact from the state and viewport or window size where that claim matters.\n- The viewport-fit checks passed for the intended initial view and any required minimum supported viewport or window size.\n- If the product launches in a window, the as-launched size, placement, and initial layout were checked before any manual resize or repositioning.\n- The UI is not just functional; it is visually coherent and not aesthetically weak for the task.\n- Functional correctness, viewport fit, and visual quality must each pass on their own; one does not imply the others.\n- A short exploratory pass was completed for interactive products, and the response mentions what that pass covered.\n- If screenshot review and numeric checks disagreed at any point, the discrepancy was investigated before signoff; visible clipping in screenshots is a failure to resolve, not something metrics can overrule.\n- Include a brief negative confirmation of the main defect classes you checked for and did not find.\n- Cleanup was executed, or you intentionally kept the session alive for further work.\n\n## Screenshot Examples\n\nIf you plan to emit a screenshot through `codex.emitImage(...)`, use the CSS-normalized paths in the next section by default. Those are the canonical examples for screenshots that will be interpreted by the model or used for coordinate-based follow-up actions. Keep raw captures as an exception for fidelity-sensitive debugging only; the raw exception examples appear after the normalization guidance.\n\n### Model-bound screenshots (default)\n\nIf you will emit a screenshot with `codex.emitImage(...)` for model interpretation, normalize it to CSS pixels for the exact region you captured before emitting. This keeps returned coordinates aligned with Playwright CSS pixels if the reply is later used for clicking, and it also reduces image payload size and model token cost.\n\nDo not emit raw native-window screenshots by default. Skip normalization only when you explicitly need device-pixel fidelity, such as Retina or DPI artifact debugging, pixel-accurate rendering inspection, or another fidelity-sensitive case where raw pixels matter more than payload size. For local-only inspection that will not be emitted to the model, raw capture is fine.\n\nDo not assume `page.screenshot({ scale: \"css\" })` is enough in native-window mode (`viewport: null`). In Chromium on macOS Retina displays, headed native-window screenshots can still come back at device-pixel size even when `scale: \"css\"` is requested. The same caveat applies to Electron windows launched through Playwright because Electron runs with `noDefaultViewport`, and `appWindow.screenshot({ scale: \"css\" })` may still return device-pixel output.\n\nUse separate normalization paths for web pages and Electron windows:\n\n- Web: prefer `page.screenshot({ scale: \"css\" })` directly. If native-window Chromium still returns device-pixel output, resize inside the current page with canvas; no scratch page is required.\n- Electron: do not use `appWindow.context().newPage()` or `electronApp.context().newPage()` as a scratch page. Electron contexts do not support that path reliably. Capture in the main process with `BrowserWindow.capturePage(...)`, resize with `nativeImage.resize(...)`, and emit those bytes directly.\n\nShared helpers and conventions:\n\n```javascript\nvar emitJpeg = async function (bytes) {\n  await codex.emitImage({\n    bytes,\n    mimeType: \"image/jpeg\",\n    detail: \"original\",\n  });\n};\n\nvar emitWebJpeg = async function (surface, options = {}) {\n  await emitJpeg(await surface.screenshot({\n    type: \"jpeg\",\n    quality: 85,\n    scale: \"css\",\n    ...options,\n  }));\n};\n\nvar clickCssPoint = async function ({ surface, x, y, clip }) {\n  await surface.mouse.click(\n    clip ? clip.x + x : x,\n    clip ? clip.y + y : y\n  );\n};\n\nvar tapCssPoint = async function ({ page, x, y, clip }) {\n  await page.touchscreen.tap(\n    clip ? clip.x + x : x,\n    clip ? clip.y + y : y\n  );\n};\n```\n\n- Use `page` or `mobilePage` for web, or `appWindow` for Electron, as the `surface`.\n- Treat `clip` as CSS pixels from `getBoundingClientRect()` in the renderer.\n- Prefer JPEG at `quality: 85` unless lossless fidelity is specifically required.\n- For full-image captures, use returned `{ x, y }` directly.\n- For clipped captures, add the clip origin back when clicking.\n\n### Web CSS normalization\n\nPreferred web path for explicit-viewport contexts, and often for web in general:\n\n```javascript\nawait emitWebJpeg(page);\n```\n\nMobile web uses the same path; substitute `mobilePage` for `page`:\n\n```javascript\nawait emitWebJpeg(mobilePage);\n```\n\nIf the model returns `{ x, y }`, click it directly:\n\n```javascript\nawait clickCssPoint({ surface: page, x, y });\n```\n\nMobile web click path:\n\n```javascript\nawait tapCssPoint({ page: mobilePage, x, y });\n```\n\nFor web `clip` screenshots or element screenshots in this normal path, `scale: \"css\"` usually works directly. Add the region origin back when clicking.\n\n- `await emitWebJpeg(page, { clip })`\n- `await emitWebJpeg(mobilePage, { clip })`\n- `await clickCssPoint({ surface: page, clip, x, y })`\n- `await tapCssPoint({ page: mobilePage, clip, x, y })`\n- `await clickCssPoint({ surface: page, clip: box, x, y })` after `const box = await locator.boundingBox()`\n\nWeb native-window fallback when `scale: \"css\"` still comes back at device-pixel size:\n\n```javascript\nvar emitWebScreenshotCssScaled = async function ({ page, clip, quality = 0.85 } = {}) {\n  var NodeBuffer = (await import(\"node:buffer\")).Buffer;\n  const target = clip\n    ? { width: clip.width, height: clip.height }\n    : await page.evaluate(() => ({\n        width: window.innerWidth,\n        height: window.innerHeight,\n      }));\n\n  const screenshotBuffer = await page.screenshot({\n    type: \"png\",\n    ...(clip ? { clip } : {}),\n  });\n\n  const bytes = await page.evaluate(\n    async ({ imageBase64, targetWidth, targetHeight, quality }) => {\n      const image = new Image();\n      image.src = `data:image/png;base64,${imageBase64}`;\n      await image.decode();\n\n      const canvas = document.createElement(\"canvas\");\n      canvas.width = targetWidth;\n      canvas.height = targetHeight;\n\n      const ctx = canvas.getContext(\"2d\");\n      ctx.imageSmoothingEnabled = true;\n      ctx.drawImage(image, 0, 0, targetWidth, targetHeight);\n\n      const blob = await new Promise((resolve) =>\n        canvas.toBlob(resolve, \"image/jpeg\", quality)\n      );\n\n      return new Uint8Array(await blob.arrayBuffer());\n    },\n    {\n      imageBase64: NodeBuffer.from(screenshotBuffer).toString(\"base64\"),\n      targetWidth: target.width,\n      targetHeight: target.height,\n      quality,\n    }\n  );\n\n  await emitJpeg(bytes);\n};\n```\n\nFor a full viewport fallback capture, treat returned `{ x, y }` as direct CSS coordinates:\n\n```javascript\nawait emitWebScreenshotCssScaled({ page });\nawait clickCssPoint({ surface: page, x, y });\n```\n\nFor a clipped fallback capture, add the clip origin back:\n\n```javascript\nawait emitWebScreenshotCssScaled({ page, clip });\nawait clickCssPoint({ surface: page, clip, x, y });\n```\n\n### Electron CSS normalization\n\nFor Electron, normalize in the main process instead of opening a scratch Playwright page. The helper below returns CSS-scaled bytes for the full content area or for a clipped CSS-pixel region. Treat `clip` as content-area CSS pixels, for example values taken from `getBoundingClientRect()` in the renderer.\n\n```javascript\nvar emitElectronScreenshotCssScaled = async function ({ electronApp, clip, quality = 85 } = {}) {\n  const bytes = await electronApp.evaluate(async ({ BrowserWindow }, { clip, quality }) => {\n    const win = BrowserWindow.getAllWindows()[0];\n    const image = clip ? await win.capturePage(clip) : await win.capturePage();\n\n    const target = clip\n      ? { width: clip.width, height: clip.height }\n      : (() => {\n          const [width, height] = win.getContentSize();\n          return { width, height };\n        })();\n\n    const resized = image.resize({\n      width: target.width,\n      height: target.height,\n      quality: \"best\",\n    });\n\n    return resized.toJPEG(quality);\n  }, { clip, quality });\n\n  await emitJpeg(bytes);\n};\n```\n\nFull Electron window:\n\n```javascript\nawait emitElectronScreenshotCssScaled({ electronApp });\nawait clickCssPoint({ surface: appWindow, x, y });\n```\n\nClipped Electron region using CSS pixels from the renderer:\n\n```javascript\nvar clip = await appWindow.evaluate(() => {\n  const rect = document.getElementById(\"board\").getBoundingClientRect();\n  return {\n    x: Math.round(rect.x),\n    y: Math.round(rect.y),\n    width: Math.round(rect.width),\n    height: Math.round(rect.height),\n  };\n});\n\nawait emitElectronScreenshotCssScaled({ electronApp, clip });\nawait clickCssPoint({ surface: appWindow, clip, x, y });\n```\n\n### Raw Screenshot Exception Examples\n\nUse these only when raw pixels matter more than CSS-coordinate alignment, such as Retina or DPI artifact debugging, pixel-accurate rendering inspection, or other fidelity-sensitive review.\n\nWeb desktop raw emit:\n\n```javascript\nawait codex.emitImage({\n  bytes: await page.screenshot({ type: \"jpeg\", quality: 85 }),\n  mimeType: \"image/jpeg\",\n  detail: \"original\",\n});\n```\n\nElectron raw emit:\n\n```javascript\nawait codex.emitImage({\n  bytes: await appWindow.screenshot({ type: \"jpeg\", quality: 85 }),\n  mimeType: \"image/jpeg\",\n  detail: \"original\",\n});\n```\n\nMobile raw emit after the mobile web context is already running:\n\n```javascript\nawait codex.emitImage({\n  bytes: await mobilePage.screenshot({ type: \"jpeg\", quality: 85 }),\n  mimeType: \"image/jpeg\",\n  detail: \"original\",\n});\n```\n\n## Viewport Fit Checks (Required)\n\nDo not assume a screenshot is acceptable just because the main widget is visible. Before signoff, explicitly verify that the intended initial view matches the product requirement, using both screenshot review and numeric checks.\n\n- Define the intended initial view before signoff. For scrollable pages, this is the above-the-fold experience. For app-like shells, games, editors, dashboards, or tools, this is the full interactive surface plus the controls and status needed to use it.\n- Use screenshots as the primary evidence for fit. Numeric checks support the screenshots; they do not overrule visible clipping.\n- Signoff fails if any required visible region is clipped, cut off, obscured, or pushed outside the viewport in the intended initial view, even if page-level scroll metrics appear acceptable.\n- Scrolling is acceptable when the product is designed to scroll and the initial view still communicates the core experience and exposes the primary call to action or required starting context.\n- For fixed-shell interfaces, scrolling is not an acceptable workaround if it is needed to reach part of the primary interactive surface or essential controls.\n- Do not rely on document scroll metrics alone. Fixed-height shells, internal panes, and hidden-overflow containers can clip required UI while page-level scroll checks still look clean.\n- Check region bounds, not just document bounds. Verify that each required visible region fits within the viewport in the startup state.\n- For Electron or desktop apps, verify both the launched window size and placement and the renderer's initial visible layout before any manual resize or repositioning.\n- Passing viewport-fit checks only proves that the intended initial view is visible without unintended clipping or scrolling. It does not prove that the UI is visually correct or aesthetically successful.\n\nWeb or renderer check:\n\n```javascript\nconsole.log(await page.evaluate(() => ({\n  innerWidth: window.innerWidth,\n  innerHeight: window.innerHeight,\n  clientWidth: document.documentElement.clientWidth,\n  clientHeight: document.documentElement.clientHeight,\n  scrollWidth: document.documentElement.scrollWidth,\n  scrollHeight: document.documentElement.scrollHeight,\n  canScrollX: document.documentElement.scrollWidth > document.documentElement.clientWidth,\n  canScrollY: document.documentElement.scrollHeight > document.documentElement.clientHeight,\n})));\n```\n\nElectron check:\n\n```javascript\nconsole.log(await appWindow.evaluate(() => ({\n  innerWidth: window.innerWidth,\n  innerHeight: window.innerHeight,\n  clientWidth: document.documentElement.clientWidth,\n  clientHeight: document.documentElement.clientHeight,\n  scrollWidth: document.documentElement.scrollWidth,\n  scrollHeight: document.documentElement.scrollHeight,\n  canScrollX: document.documentElement.scrollWidth > document.documentElement.clientWidth,\n  canScrollY: document.documentElement.scrollHeight > document.documentElement.clientHeight,\n})));\n```\n\nAugment the numeric check with `getBoundingClientRect()` checks for the required visible regions in your specific UI when clipping is a realistic failure mode; document-level metrics alone are not sufficient for fixed shells.\n\n## Dev Server\n\nFor local web debugging, keep the app running in a persistent TTY session. Do not rely on one-shot background commands from a short-lived shell.\n\nUse the project's normal start command, for example:\n\n```bash\nnpm start\n```\n\nBefore `page.goto(...)`, verify the chosen port is listening and the app responds.\n\nFor Electron debugging, launch the app from `js_repl` through `_electron.launch(...)` so the same session owns the process. If the Electron renderer depends on a separate dev server (for example Vite or Next), keep that server running in a persistent TTY session and then relaunch or reload the Electron app from `js_repl`.\n\n## Cleanup\n\nOnly run cleanup when the task is actually finished:\n\n- This cleanup is manual. Exiting Codex, closing the terminal, or losing the `js_repl` session does not implicitly run `electronApp.close()`, `context.close()`, or `browser.close()`.\n- For Electron specifically, assume the app may keep running if you leave the session without executing the cleanup cell first.\n\n```javascript\nif (electronApp) {\n  await electronApp.close().catch(() => {});\n}\n\nif (mobileContext) {\n  await mobileContext.close().catch(() => {});\n}\n\nif (context) {\n  await context.close().catch(() => {});\n}\n\nif (browser) {\n  await browser.close().catch(() => {});\n}\n\nbrowser = undefined;\ncontext = undefined;\npage = undefined;\nmobileContext = undefined;\nmobilePage = undefined;\nelectronApp = undefined;\nappWindow = undefined;\n\nconsole.log(\"Playwright session closed\");\n```\n\nIf you plan to exit Codex immediately after debugging, run the cleanup cell first and wait for the `\"Playwright session closed\"` log before quitting.\n\n## Common Failure Modes\n\n- `Cannot find module 'playwright'`: run the one-time setup in the current workspace and verify the import before using `js_repl`.\n- Playwright package is installed but the browser executable is missing: run `npx playwright install chromium`.\n- `page.goto: net::ERR_CONNECTION_REFUSED`: make sure the dev server is still running in a persistent TTY session, recheck the port, and prefer `http://127.0.0.1:<port>`.\n- `electron.launch` hangs, times out, or exits immediately: verify the local `electron` dependency, confirm the `args` target, and make sure any renderer dev server is already running before launch.\n- `Identifier has already been declared`: reuse the existing top-level bindings, choose a new name, or wrap the code in `{ ... }`. Use `js_repl_reset` only when the kernel is genuinely stuck.\n- `browserContext.newPage: Protocol error (Target.createTarget): Not supported` while working with Electron: do not use `appWindow.context().newPage()` or `electronApp.context().newPage()` as a scratch page; use the Electron-specific screenshot normalization flow in the model-bound screenshots section.\n- `js_repl` timed out or reset: rerun the bootstrap cell and recreate the session with shorter, more focused cells.\n- Browser launch or network operations fail immediately: confirm the session was started with `--sandbox danger-full-access` and restart that way if needed.\n\nFile v1.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn75th2nak68tgaabrdejxj91h82ff1a\",\n  \"slug\": \"playwright-interactive\",\n  \"version\": \"1.0.0\",\n  \"publishedAt\": 1776548168042\n}\n\nFile v1.0.0:skill-card.md\n\n## Description:\n\nPersistent browser and Electron interaction through js_repl for fast iterative UI debugging.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[tridefender](https://clawhub.ai/user/tridefender)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and engineers use this skill to keep Playwright browser or Electron sessions alive while debugging local user interfaces, running functional checks, and capturing visual QA evidence.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The workflow asks users to disable sandbox protection for Playwright and js_repl use.\n\nMitigation: Use the skill only in trusted local workspaces and prefer an isolated VM or container when testing unfamiliar code.\n\nRisk: The workflow installs runtime dependencies and may launch local web or Electron applications.\n\nMitigation: Avoid unknown repositories, pull requests, downloaded Electron apps, and environments containing sensitive credentials.\n\nRisk: The server security verdict is suspicious.\n\nMitigation: Review the skill and its dependencies before deployment, and use pinned dependencies where possible.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/tridefender/skills/playwright-interactive)\n- [ClawHub publisher profile](https://clawhub.ai/user/tridefender)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, markdown, code, shell commands, configuration]\n\n**Output Format:** [Markdown instructions with JavaScript, shell, and TOML code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces workflow guidance for persistent Playwright and Electron QA sessions; it does not produce standalone application artifacts.]\n\n## Skill Version(s):\n\n1.0.0 (source: server-resolved release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.0.0:agents/openai.yaml\n\ninterface:\n  display_name: \"Playwright Interactive\"\n  short_description: \"Persistent browser and Electron QA\"\n  icon_small: \"./assets/playwright-small.svg\"\n  icon_large: \"./assets/playwright.png\"\n  default_prompt: \"Use $playwright-interactive to debug a local web or Electron app in a persistent Playwright session and capture the QA evidence.\"\n\nFile v1.0.0:LICENSE.txt\n\nApache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright (c) Microsoft Corporation.\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\n\nFile v1.0.0:NOTICE.txt\n\nThis skill reuses the Playwright icon assets from `.codex/skills/playwright/assets/`.\n\nThe local `playwright` skill attributes those assets to the Microsoft\n`playwright-cli` repository.\n\nCopyright (c) Microsoft Corporation.\n\nLicensed under the Apache License, Version 2.0.\nSee LICENSE.txt in this directory.\n\nModifications:\n- Repackaged the existing repository Playwright assets for this `js_repl`-focused skill.\n- Wrote new skill instructions for persistent browser debugging.","readmeExcerpt":"Skill: Playwright Interactive Owner: tridefender Summary: Persistent browser and Electron QA Tags: latest:1.0.0 Version history: v1.0.0 | 2026-04-18T21:36:08.042Z | auto Initial release: Adds persistent Playwright + Electron browser interaction through js_repl for rapid, iterative UI debugging. - Supports persistent Playwright sessions with shared browser handles—avoids repeated launching, improving iteration speed. ","codeSnippets":[],"executableExamples":[{"language":"toml","snippet":"[features]\njs_repl = true"},{"language":"bash","snippet":"test -f package.json || npm init -y\nnpm install playwright\n# Web-only, for headed Chromium or mobile emulation:\n# npx playwright install chromium\n# Electron-only, and only if the target workspace is the app itself:\n# npm install --save-dev electron\nnode -e \"import('playwright').then(() => console.log('playwright import ok')).catch((error) => { console.error(error); process.exit(1); })\""},{"language":"javascript","snippet":"var chromium;\nvar electronLauncher;\nvar browser;\nvar context;\nvar page;\nvar mobileContext;\nvar mobilePage;\nvar electronApp;\nvar appWindow;\n\ntry {\n  ({ chromium, _electron: electronLauncher } = await import(\"playwright\"));\n  console.log(\"Playwright loaded\");\n} catch (error) {\n  throw new Error(\n    `Could not load playwright from the current js_repl cwd. Run the setup commands from this workspace first. Original error: ${error}`\n  );\n}"},{"language":"javascript","snippet":"var resetWebHandles = function () {\n  context = undefined;\n  page = undefined;\n  mobileContext = undefined;\n  mobilePage = undefined;\n};\n\nvar ensureWebBrowser = async function () {\n  if (browser && !browser.isConnected()) {\n    browser = undefined;\n    resetWebHandles();\n  }\n\n  browser ??= await chromium.launch({ headless: false });\n  return browser;\n};\n\nvar reloadWebContexts = async function () {\n  for (const currentContext of [context, mobileContext]) {\n    if (!currentContext) continue;\n    for (const p of currentContext.pages()) {\n      await p.reload({ waitUntil: \"domcontentloaded\" });\n    }\n  }\n  console.log(\"Reloaded existing web tabs\");\n};"},{"language":"javascript","snippet":"var TARGET_URL = \"http://127.0.0.1:3000\";\n\nif (page?.isClosed()) page = undefined;\n\nawait ensureWebBrowser();\ncontext ??= await browser.newContext({\n  viewport: { width: 1600, height: 900 },\n});\npage ??= await context.newPage();\n\nawait page.goto(TARGET_URL, { waitUntil: \"domcontentloaded\" });\nconsole.log(\"Loaded:\", await page.title());"},{"language":"javascript","snippet":"var MOBILE_TARGET_URL = typeof TARGET_URL === \"string\"\n  ? TARGET_URL\n  : \"http://127.0.0.1:3000\";\n\nif (mobilePage?.isClosed()) mobilePage = undefined;\n\nawait ensureWebBrowser();\nmobileContext ??= await browser.newContext({\n  viewport: { width: 390, height: 844 },\n  isMobile: true,\n  hasTouch: true,\n});\nmobilePage ??= await mobileContext.newPage();\n\nawait mobilePage.goto(MOBILE_TARGET_URL, { waitUntil: \"domcontentloaded\" });\nconsole.log(\"Loaded mobile:\", await mobilePage.title());"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: \"playwright-interactive\"\ndescription: \"Persistent browser and Electron interaction through `js_repl` for fast iterative UI debugging.\"\n---\n\n# Playwright Interactive Skill\n\nUse a persistent `js_repl` Playwright session to debug local web or Electron apps, keep the same handles alive across iterations, and run functional plus visual QA without restarting the whole toolchain unless the process ownership changed.\n\n## Preconditions\n\n- `js_repl` must be enabled for this skill.\n- If `js_repl` is missing, enable it in `~/.codex/config.toml`:\n\n```toml\n[features]\njs_repl = true\n```\n\n- You can also start a new session with `--enable js_repl` (equivalent to `-c features.js_repl=true`).\n- After enabling `js_repl`, start a new Codex session so the tool list refreshes.\n- For now, run this workflow with sandboxing disabled: start Codex with `--sandbox danger-full-access` (or the equivalent config for `sandbox_mode=danger-full-access`). This is a temporary requirement while `js_repl` + Playwright support inside the sandbox is still being completed.\n- Run setup from the same project directory you need to debug.\n- Treat `js_repl_reset` as a recovery tool, not routine cleanup. Resetting the kernel destroys your Playwright handles.\n\n## One-time setup\n\n```bash\ntest -f package.json || npm init -y\nnpm install playwright\n# Web-only, for headed Chromium or mobile emulation:\n# npx playwright install chromium\n# Electron-only, and only if the target workspace is the app itself:\n# npm install --save-dev electron\nnode -e \"import('playwright').then(() => console.log('playwright import ok')).catch((error) => { console.error(error); process.exit(1); })\"\n```\n\nIf you switch to a different workspace later, repeat setup there.\n\n## Core Workflow\n\n1. Write a brief QA inventory before testing:\n   - Build the inventory from three sources: the user's requested requirements, the user-visible features or behaviors you actually implemented, and the claims you expect to make in the final response.\n   - Anything that appears in any of those three sources must map to at least one QA check before signoff.\n   - List the user-visible claims you intend to sign off on.\n   - List every meaningful user-facing control, mode switch, or implemented interactive behavior.\n   - List the state changes or view changes each control or implemented behavior can cause.\n   - Use this as the shared coverage list for both functional QA and visual QA.\n   - For each claim or control-state pair, note the intended functional check, the specific state where the visual check must happen, and the evidence you expect to capture.\n   - If a requirement is visually central but subjective, convert it into an observable QA check instead of leaving it implicit.\n   - Add at least 2 exploratory or off-happy-path scenarios that could expose fragile behavior.\n2. Run the bootstrap cell once.\n3. Start or confirm any required dev server in a persistent TTY session.\n4. Launch the correct runtime and keep reusing the same Playwr"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn75th2nak68tgaabrdejxj91h82ff1a\",\n  \"slug\": \"playwright-interactive\",\n  \"version\": \"1.0.0\",\n  \"publishedAt\": 1776548168042\n}"},{"path":"skill-card.md","content":"## Description:\n\nPersistent browser and Electron interaction through js_repl for fast iterative UI debugging.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[tridefender](https://clawhub.ai/user/tridefender)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and engineers use this skill to keep Playwright browser or Electron sessions alive while debugging local user interfaces, running functional checks, and capturing visual QA evidence.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The workflow asks users to disable sandbox protection for Playwright and js_repl use.\n\nMitigation: Use the skill only in trusted local workspaces and prefer an isolated VM or container when testing unfamiliar code.\n\nRisk: The workflow installs runtime dependencies and may launch local web or Electron applications.\n\nMitigation: Avoid unknown repositories, pull requests, downloaded Electron apps, and environments containing sensitive credentials.\n\nRisk: The server security verdict is suspicious.\n\nMitigation: Review the skill and its dependencies before deployment, and use pinned dependencies where possible.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/tridefender/skills/playwright-interactive)\n- [ClawHub publisher profile](https://clawhub.ai/user/tridefender)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, markdown, code, shell commands, configuration]\n\n**Output Format:** [Markdown instructions with JavaScript, shell, and TOML code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces workflow guidance for persistent Playwright and Electron QA sessions; it does not produce standalone application artifacts.]\n\n## Skill Version(s):\n\n1.0.0 (source: server-resolved release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."},{"path":"agents/openai.yaml","content":"interface:\n  display_name: \"Playwright Interactive\"\n  short_description: \"Persistent browser and Electron QA\"\n  icon_small: \"./assets/playwright-small.svg\"\n  icon_large: \"./assets/playwright.png\"\n  default_prompt: \"Use $playwright-interactive to debug a local web or Electron app in a persistent Playwright session and capture the QA evidence.\""},{"path":"LICENSE.txt","content":"Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, "}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Persistent browser and Electron QA Skill: Playwright Interactive Owner: tridefender Summary: Persistent browser and Electron QA Tags: latest:1.0.0 Version history: v1.0.0 | 2026-04-18T21:36:08.042Z | auto Initial release: Adds persistent Playwright + Electron browser interaction through js_repl for rapid, iterative UI debugging. - Supports persistent Playwright sessions with shared browser handles—avoids repeated launching, improving iteration speed.","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1530,"uniquenessScore":47,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T22:54:16.154Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T22:54:16.154Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-12T19:33:23.484Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}