main
Kyle Bergstedt Publish 3.0.0 259e308 13d ago

name: pup-lanes user-invocable: false description: "Parent skill: pup. The two ways pup drives a pup window (never name the browser build to a user), the extension lane (DEFAULT, every vendor site loads, no debug port) and the CDP lane (opt-in ONLY via lane:'cdp', full DevTools control but detectable and walled by vendor edges). Pros and cons of each, exactly which verbs need CDP, what lane:'cdp' costs (it takes adom-you away from the extension lane and closes its windows), and the rule: the extension lane already has CDP-level access (pup_devtools sends any DevTools command), so never stop or move a task because the CDP lane is off. Read before passing lane, isolated, profile, highFps or webSecurity to pup_open_window, and whenever a verb answers lane_needs_cdp or cdp_lane_required. Trigger words: pup lane, extension lane, cdp lane, lane:cdp, lane_needs_cdp, cdp_lane_required, which lane, remote-debugging-port, debug port detected, site blocks pup, pup_open_window lane, isolated:true refused, highFps refused, three icons vs four icons."

pup lanes: the extension lane is pup. CDP is the exception.

The point of the September 2026 work (John, 2026-09-13 and 14) was one thing: pup windows that load EVERY website without the site blocking us. That turned out to be the extension lane. So it is the default, and the CDP lane opens only when an AI writes lane:"cdp" because the task needs something only CDP can do AND the user has turned that lane on for the box (cdpLane, off by default since 2.0.652: cdp_lane_disabled otherwise). pup no longer falls back to CDP on its own for any reason.

What each lane is

Extension lane (DEFAULT) CDP lane (lane:"cdp", opt-in)
How pup drives the window pup's own MV3 extension polls the bridge and runs the commands inside Chrome Chrome DevTools Protocol over --remote-debugging-port
Debug port none yes, and vendor edges detect it (measured: st.com and mouser RST the HTTP/2 stream, arrow denies)
Profile one browser per profile: adom-you is shared by every thread; isolated:true and profile:"<name>" get their own lane browser, extension and queue (2.0.659) any profile; on adom-you it TAKES the profile from the extension lane and closes those windows
Toolbar four icons: pup dots, pen, identity tile, nbe three icons (nbe rides the extension lane only)
Taskbar identity, tiles, overlays, jump lists none on macOS (no per-window taskbar button) none on macOS
Annotate (pen, snip) yes (2.0.569, Trusted-Types safe since 2.0.570) yes
Vendor sites (st, mouser, digikey, arrow, analog, ti, avnet, nxp, infineon, and the rest of the 20) load walled by several of them

Pros and cons

Extension lane

  • Pro: sites load. This is the reason it exists and the reason it is the default.
  • Pro: one shared adom-you browser, so logins and cookies accumulate for every thread, and every window carries the full toolbar including nbe.
  • Con: pup_eval runs in the page's MAIN world, so a page with a strict Content-Security-Policy (wiki.adom.inc, claude.ai) refuses it with "Evaluating a string as JavaScript violates the following Content Security Policy". Use pup_screenshot, pup_list_tabs, pup_navigate and the other DOM-free verbs there, or lane:"cdp" if you truly must run script on such a page and accept that vendor sites will not load in that window.
  • Note on screenshots: a window that produces no frames cannot be captured. On macOS the windows of a hidden app stop producing frames after about a minute, so every capture briefly unhides pup's own browser app BEHIND the user's frontmost app (no activation, never over the user's window) and re-hides it afterwards, one shared unhide for concurrent captures. captureVisibleTab is raced against a 3 s deadline and falls back to a debugger frame. The lane also launches with CalculateNativeWinOcclusion disabled, so a covered window keeps compositing. Background TABS are still throttled by Chrome as before; this is not the highFps anti-throttle set.
  • Since 2.0.578 the extension lane ALSO has trusted input (pup_click, pup_hover, pup_type, pup_press_key, pup_scroll, pup_fill), element and full-resolution screenshots, pup_select (a <select> by value or label, 2.0.592), and CSP-proof pup_eval (a page whose Content-Security-Policy or Trusted Types policy refuses the injected eval is retried through DevTools automatically, 2.0.591; Google Calendar and Admin are the everyday cases). They ride nbe's DevTools driver inside the lane (chrome.debugger, attached to one tab on demand, detached after nbe's idle window; no debug port, no automation flag, navigator.webdriver stays false, no bar). Since 2.0.581 recording (pup_record_start / pup_record_stop) works on this lane too: it rides ab's native recorder (Windows Graphics Capture, hardware H.264 MP4, keyed on the window handle), which records a covered window live and emits frames only when the content changes. Still CDP-only: selector-driven pup_download, realKeystrokes logins, iframe targeting, separate profiles (backlog: pup-bridge#113), highFps, webSecurity:false. Those answer lane_needs_cdp with the fix.

CDP lane

  • Pro: everything DevTools can do: trusted mouse and keyboard events, cross-origin iframes, Runtime.evaluate that ignores page CSP, element and full-res screenshots, annotate, recording, emulation, anti-throttle for a live view.
  • Con: the debug port is a detection surface. A CDP window is what gets you "Access Denied" on the hard vendor sites.
  • Con: lane:"cdp" on adom-you evicts the extension lane: pup closes every extension-lane window to hand the profile over, because Chrome runs one process per profile. Other threads lose their windows. That is why it is opt-in.
  • Con: three toolbar icons, no nbe.

The rule

  1. Open windows with no lane. You get the extension lane.
  2. profile and isolated need no lane (2.0.659: their own extension-lane browser). Only highFps and webSecurity:false still need lane:"cdp"; without it pup refuses with cdp_lane_required and says why. Since 2.0.563 nothing silently opens on CDP.
  3. You almost never need lane:"cdp": the extension lane speaks the full DevTools protocol through pup's extension, and pup_devtools {method, params} sends any command to an extension-lane window. Since 2.0.726, lane:"cdp" on a box with the CDP lane off opens on the extension lane with a _laneNote instead of refusing; never stop, and never move the task to another box, because CDP is off. A pup update reaches a running extension lane on its own: pup re-stages the extension, cycles the lane browser and relaunches every window from its file on the new extension (2.0.647; the 2.0.569 in-place reload broke the channel and is gone), so a new build takes effect without anyone closing a window. pup_status.extensionLane.workerVersion shows what the lane is running.
  4. If a verb says something is not wired on the extension lane yet, its hint names the extension-lane way (a URL download, pup_type for a stubborn form, pup_devtools for iframes and anything else). Use that, and file the gap on adom/pup-bridge.

How you tell them apart

The toolbar: four icons is the extension lane, three is CDP (John's own spec for the fourth icon). pup_list_windows reports transport: "ext" or "cdp" per window. pup_status.extensionLane shows the lane's health.

What the extension lane can do since 2.0.648 (it used to say lane_needs_cdp)

  • Trusted input: pup_input_dispatch {type:"click"|"mouseMoved"|"mousePressed"|"mouseReleased"|"mouseWheel"|"keyDown"|"keyUp"|"rawKeyDown"|"char", x, y, ...} works on the extension lane through the worker's DevTools driver, so the event is as trusted as the CDP lane's and lands inside cross-origin frames. Measured 2026-09-19: a click on the reCAPTCHA demo checkbox passed it and issued a token, no image grid. Captchas are driven here, never on the CDP lane and never handed to the human (the user's rule); the image-grid loop (screenshot, pick tiles, trusted tile clicks, Verify) is the caller's script on top of these verbs.
  • pup_fetch_url runs in the named tab on this lane, tries the fetch with credentials and then without (a wildcard CORS header refuses credentials), returns httpStatus, contentType, bytes, sha256, and the body as bodyBase64 (binary-safe) or text. saveTo takes your container path: the CLI writes the file from the returned body and reports savedTo plus savedToFilesystem:"container"; compare sha256 (measured: a 269669-byte PDF, identical hash to the reporter's). A cancelled HTTP auth challenge comes back as no_credential with the host.
  • isolated:true mints a throwaway iso-<id> profile (reported by pup_window_info), opens it in its OWN extension-lane browser (2.0.659, pup-bridge#113), and ends that browser and removes the profile when the window closes. No lane argument, no CDP. Measured: an isolated window on the extension lane read an empty cookie jar while a default-lane window kept working beside it.
  • Slow boxes: a cold pup_open_window that would exceed ab's budget answers ok:true, loading:true with a progress frame once the window exists and finishes the navigate in the background; poll pup_window_info instead of opening again.

The CDP lane is OFF by default (2.0.652, John 2026-09-19)

pup_open_window {lane:"cdp"} opens on the extension lane (with a _laneNote) unless the user has turned the CDP lane on for that box with pup_configure {cdpLane:"on"}; before 2.0.726 it refused with cdp_lane_disabled, and AIs read that as "pup can't do this here". John: "i want it almost NEVER used cuz then you may use it as a crutch instead of fixing ext lane to solve all use cases." Trusted input, HTTP auth, fetch, screenshots and recording all run on the extension lane; a feature that genuinely needs CDP is an extension-lane gap to file on adom/pup-bridge, not a reason to open a CDP window. isolated:true and profile:"<name>" run on the extension lane too (2.0.659): each profile gets its own lane browser, its own staged extension and queue, so an isolated window is a separate browser with an empty jar, and a throwaway one ends with its last window.

Windows keep their profile and their record across restarts (2.0.669 to 2.0.671)

Each profile has its own extension-lane browser (adom-you, plus one per explicit profile). On 2026-09-21 John saw windows lose their record after an upgrade on his laptop, and the cause was two bugs:

  • A window still on screen was forgotten. After an upgrade the recovery pass counted each 15 s "still on screen, extension not answering yet" check as a failed relaunch and deleted the window's record on the third. The window stayed up with no owner, and its thread opened a duplicate. Since 2.0.669 a window on screen is never counted as a failure; its record is kept until it is re-adopted.
  • A browser was adopted into the wrong profile. At boot pup restored only the adom-you lane, and the first unknown lane browser to say hello became adom-you, whatever folder it ran. adom-you windows then opened inside the "services" browser, with that profile's cookies. Since 2.0.670/671: every profile's lane is restored at boot and trusted only when its processes really run that profile's folder; the extension reports its profile in every hello, and an unknown browser is adopted only into that profile's lane, only after the boot restore; each window is re-adopted on its own profile's lane; and a window found inside another profile's browser is closed there and reopened in its own profile, at its page, in the background.

Proven on CRR with an adom-you window plus a second-profile window through an upgrade and a plain restart (both kept, each in its own profile's browser, same windows), and on AdomLapper, where the three misplaced adom-you windows were moved back into the adom-you browser automatically.

Multi-tab windows after an upgrade (2.0.676). An upgrade cycles the lane browser and reopens every window with its tabs. Two bugs showed on AdomLapper on 2026-09-22: the extension opened a new tab in whatever window had a real page when it could not find the named one, so 6 of one thread's tabs landed in another thread's window; and the reopen de-duplicated URLs with the query removed, so different pages on one path (two YouTube videos) collapsed into one. Now a new tab opens only in the window pup names (a live tab of it, or its Chrome window id) and the extension refuses with window_not_found rather than guess; duplicates are exact URLs only. Proven on CRR: a 4-tab window and a 1-tab window from another thread both came back complete and separate.

The user's close is final, even during a restart or an upgrade (2.0.684)

On 2026-09-23 John closed the NSF thread's window on his laptop and it reopened, twice. An upgrade had ended pup's browser and was relaunching his windows one at a time; each close landed between two relaunches, so the thread's next window came back 13 to 28 s later. The rules now:

  • pup relaunches a missing window ONLY when it knows that window's browser died for this pass: pup ended it (an upgrade or pup_restart_browser), it crashed, or it was already dead when pup booted. Those windows are marked lost before anything relaunches.
  • Any other missing window, one whose browser is running without it, was CLOSED. pup forgets it and never brings it back. This covers a close that happens while pup itself is restarting and cannot hear the extension.
  • Closing a window while a relaunch queue runs cancels every queued relaunch of the same thread, and each relaunch first picks up closes reported since the previous one.

Do not decide "closed vs lost" from whether a browser is running NOW: the first relaunch of an upgrade restarts the browser, and 2.0.681, which did exactly that, dropped every window after the first on every upgrade (caught on CRR before it went public). Proven on CRR with three windows of one thread: an upgrade brings all three back, closing the first mid-queue cancels the other two, and a window closed during a restart stays closed.