app
Pup - the AI's own browser
Public Made by Adomby adom
pup gives your AI a real browser on your desktop that it drives completely, in the background, signed in as you: windows that never jump in front of your work, one shared profile that learns your logins, and every window labeled on the taskbar with its AI thread's name.
master
John Lauer
docs/contract: golden fixtures recorded from the Node build 2.0.399 for the Rust port
71c0e87
1mo ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801
{
"_hint": "This list — the bridge's verbs + schemas + hints, for AD's Verbs tab. Read it once to learn the surface.",
"_next": [
"pup_status"
],
"_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure — the work usually keeps running on the bridge. Poll `pup_readiness` until it reports done.",
"bridge": "puppeteer",
"durationMs": 58,
"error": "",
"output": "{\"_hint\":\"This list — the bridge's verbs + schemas + hints, for AD's Verbs tab. Read it once to learn the surface.\",\"_next\":[\"pup_status\"],\"_timeoutHint\":\"ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure — the work usually keeps running on the bridge. Poll `pup_readiness` until it reports done.\",\"bridge\":\"puppeteer\",\"progressContract\":{\"activeKey\":\"active\",\"blockedByPhases\":[\"consent\",\"dialog\"],\"blockedOnUser\":{\"errorCode\":\"blocked_on_user\",\"inVerbWaitSec\":45,\"promptLifetimeSec\":120,\"rule\":\"ab BRIDGE_SDK 2.1.30: a verb parked on a HUMAN never bare-timeouts; it answers this shape\",\"stillRunning\":\"true = the wait continues in the background: re-call the SAME verb with the SAME args to re-attach (no second prompt) or watch pup_readiness.active[]; false = the human must act first, then re-issue the verb\"},\"slowVerbs\":[\"pup_open_window\",\"pup_prewarm\",\"pup_use\"],\"statusVerb\":\"pup_readiness\",\"timings\":{\"open_window_warm\":{\"confidence\":\"measured\",\"estimatedSec\":11,\"samples\":20}}},\"related\":[\"pup_status\"],\"statusVerb\":\"pup_readiness\",\"success\":true,\"timeoutSeconds\":60,\"verbs\":[{\"example\":{},\"hint\":\"START HERE for window management: everything YOUR thread owns — windows, tabs, urls, titles, state — with ready-to-run next steps. Zero args. You NEVER need an hwnd, desktop_find_window, or desktop_screenshot_window for a pup window: pup keys every window to its owning --ai-thread name and resolves ids for you — omit sessionId in any pup verb to target your own window, or pass \\\"ai-thread\\\" to address a thread by name (the CLI's --ai-thread flag, same spelling). pup_screenshot {} screenshots it; pup_reload {} refreshes it.\",\"input\":{\"ai-thread\":\"optional str — inspect another thread's windows (read-only listing); default = the calling thread. The CLI flag's exact spelling; aiThread also accepted\"},\"longRunning\":false,\"name\":\"pup_my_windows\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"START HERE for window management: everything YOUR thread owns — windows, tabs, urls, titles, state — with ready-to-run next steps. Zero args. You NEVER need an hwnd, desktop_find_window, or desktop_screenshot_window for a pup window: pup keys every window to its owning --ai-thread name and resolves ids for you — omit sessionId in any pup verb to target your own window, or pass \\\"ai-thread\\\" to address a thread by name (the CLI's --ai-thread flag, same spelling). pup_screenshot {} screenshots it; pup_reload {} refreshes it.\",\"timeoutSeconds\":10},{\"example\":{\"height\":540,\"owner\":\"mytask\",\"sessionId\":\"mytask-web\",\"url\":\"https://example.com\",\"width\":960},\"hint\":\"Opens a generic, fully-controllable pup window (a fresh isolated Chrome/Edge process — never your real signed-in browser) that you then drive by sessionId. To drive the user's REAL Chrome/Edge, use the Adom browser extension's nbrowser_* verbs instead.\",\"input\":{\"appIconB64\":\"optional base64 PNG — override the app icon worn in the taskbar overlay. Usually UNNECESSARY: pup auto-fetches the page's own <link rel=\\\"icon\\\"> favicon (the adom-ui-design standard artifact every app must serve) and wears it automatically. An app-looking URL with NO favicon gets a reprimand hint.\",\"appName\":\"optional str — the APP this window is driving (e.g. \\\"shotlog\\\"); shown in the hover tooltip\",\"autoFlash\":\"optional bool (default true) — mutating verbs auto-flash this window's taskbar (debounced, never steals focus) so the user notices the agent touched it; pass false to make this window silent by default\",\"foreground\":\"optional bool — request showing the window on the user's screen. GATED (v1.8.70): requires foregroundReason too, else the open succeeds but stays BACKGROUND with foregroundDenied set. Only when the USER explicitly asked to watch.\",\"foregroundReason\":\"required WITH foreground:true — quote/paraphrase what the user said that justifies putting a window on their screen (min 10 chars; logged + recorded in lastAgentUpdate, auditable)\",\"height\":\"optional int px\",\"isolated\":\"optional bool — private throwaway profile: fresh-login tests, acting as a different user. REASON-GATED (v2.0.101): requires isolationReason or the open is refused — every window defaults to the shared adom-you profile\",\"isolationReason\":\"required WITH isolated:true — why this window must NOT ride the shared adom-you profile (min 10 chars; logged, auditable). webSecurity:false and wikiView:public carry their own built-in reason\",\"owner\":\"optional str — your thread/task label; lets pup protect this window from other threads\",\"profile\":\"optional str — a named durable jar; DEFAULT is the shared \\\"adom-you\\\" profile (signed-in state shared across windows). isolated:true overrides to a throwaway\",\"sessionId\":\"optional str — OMIT IT (recommended): your thread gets its OWN window keyed on your --ai-thread name; the first open creates it, later opens become TABS in it, and no other thread can touch it. Pass an explicit id only when you need a SEPARATE window (task-prefix it, e.g. \\\"mytask-web\\\")\",\"silent\":\"optional bool — suppress the auto-flash for just this call\",\"takeover\":\"optional bool — claim a window owned by another thread (only when the user explicitly asks)\",\"updateNote\":\"optional str — a short \\\"what I did\\\" note, surfaced back in list_tabs/list_windows as lastAgentUpdate so the user knows what changed\",\"url\":\"optional str\",\"webSecurity\":\"optional false — dev escape hatch for cross-origin eval; FORCES isolation so insecure flags never touch the credentialed profile\",\"width\":\"optional int px — sizes for screenshot framing, stays background\",\"wikiView\":\"optional \\\"authed\\\"|\\\"public\\\" — for wiki.adom.inc URLs. THREE distinct cases: (1) OMIT = the shared adom-you profile, LOGGED IN as the user if they have signed into the wiki (the usual case); this is NOT anonymous. (2) \\\"public\\\" = the SERVER renders the page exactly as a signed-out visitor sees it via the ?view=public param (adom/wiki#126: request user nulled, byte-identical to logged-out, private pages 404) — the window STAYS on the shared profile, session untouched, no isolated jar; use this to verify a publish did not leak private source. (3) \\\"authed\\\" = the explicit logged-in view (30-day SSO; first use may need a one-time login — response says wikiLoginNeeded). To compare \\\"what I see\\\" vs \\\"what the world sees\\\", open one \\\"authed\\\" (or omit) AND one \\\"public\\\" tab — do NOT rely on omit for the public view.\",\"x\":\"optional int px\",\"y\":\"optional int px\"},\"longRunning\":false,\"name\":\"pup_open_window\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"sessionId is OPTIONAL: omit it and your thread gets its OWN window (keyed on your --ai-thread name; later opens become tabs in it). Pass one only for a deliberate separate window — it is then your handle for every later call\",\"profile defaults to the durable shared 'adom-you' profile (logins/localStorage persist + are shared across all pup windows); isolated:true for a private throwaway — omit it for a plain \\\"open in pup\\\"\",\"sessionIds are SHARED across all AI threads on this desktop — a generic id (\\\"wiki\\\", \\\"test\\\") may collide with another thread's window and navigating it away steals their work. Use a task-prefixed sessionId + pass owner:\\\"<your-task>\\\" so pup can protect it\",\"reusing an existing sessionId with a new url NAVIGATES that window — check pup_status (shows owner per window) first if unsure\"],\"related\":[\"pup_navigate\",\"pup_list_windows\",\"pup_close_window\"],\"statusVerb\":null,\"summary\":\"Open a generic pup window — a fresh isolated Chrome/Edge process (never your real signed-in browser), fully drivable via CDP. ALWAYS opens in the BACKGROUND (does not steal focus; never disturbs the user's main work; still fully screenshottable/drivable) UNLESS you pass foreground:true — do that ONLY when the user explicitly wants to watch. Pass width+height (+ optional x,y, screen px) to place it at a specific size/position for screenshot framing — this NO LONGER foregrounds it (sizing stays in the background too; default unsized is maximized). profile defaults to the durable shared 'adom-you' profile (logins/localStorage persist + are shared across all pup windows); isolated:true for a private throwaway. OWNERSHIP: sessionIds are shared across ALL AI threads — use a task-prefixed sessionId + owner:\\\"<your-task>\\\" so pup can refuse other threads stealing your window (reusing an existing id with a new url navigates it away; declared cross-owner reuse errors with session_owned_by_another_thread unless takeover:true). (For the user's REAL Chrome/Edge, use the Adom extension's nbrowser_* verbs.)\",\"timeoutSeconds\":60},{\"example\":{\"sessionId\":\"work\",\"url\":\"https://example.com\"},\"hint\":\"Adds a tab to an existing session; returns the new tabId.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"silent\":\"optional bool — suppress the auto-flash for this call\",\"updateNote\":\"optional str — short \\\"what I did\\\" note surfaced in list_tabs as lastAgentUpdate\",\"url\":\"optional str\"},\"longRunning\":false,\"name\":\"pup_open_tab\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"the session must already exist (pup_open_window first)\"],\"related\":[\"pup_switch_tab\",\"pup_list_tabs\",\"pup_close_tab\"],\"statusVerb\":null,\"summary\":\"Open a new tab in an EXISTING session/window (returns {tabId, tabCount, activeTabId} — no need to diff list_tabs). This is the right verb for multi-URL work: ONE window with many tabs (one taskbar button), not many windows. The window stays in the background; the tab auto-flashes the taskbar (debounced) so the user notices. The USER can click the window's taskbar button at any time to view it — pup never pulls it back down.\",\"timeoutSeconds\":30},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Closes one tab; the session stays open.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"tabId\":\"optional str (default active)\"},\"longRunning\":false,\"name\":\"pup_close_tab\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"omit tabId to close the active tab — closing the last tab may close the window\"],\"related\":[\"pup_close_window\",\"pup_list_tabs\"],\"statusVerb\":null,\"summary\":\"Close a tab.\",\"timeoutSeconds\":15},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Closes the whole session and all its tabs. Destructive.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_close_window\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"this ends the session — its sessionId is no longer valid afterward\"],\"related\":[\"pup_list_windows\"],\"statusVerb\":null,\"summary\":\"Close a window/session (its tabs go too).\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"Everything about ONE pup window as JSON — owner AI thread, container, profile, tabs, age, last agent action, and the window's hwnd (for desktop_screenshot_window when you need the browser chrome in frame). For an AI caller this is a PURE DATA query: nothing is drawn on the user's screen. Visual surfaces are user-initiated only — a jump-list click shows the native taskbar caption, a toolbar-popup click shows the in-page floaty card. showCaption:true opts an AI caller into the caption ONLY when the user asked to have the window identified on screen. Read-only, never owner-gated.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"showCaption\":\"optional bool — draw the ~12s taskbar caption too; ONLY when the user asked to see which window this is\"},\"longRunning\":false,\"name\":\"pup_window_info\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Everything about ONE pup window as JSON — owner AI thread, container, profile, tabs, age, last agent action, and the window's hwnd (for desktop_screenshot_window when you need the browser chrome in frame). For an AI caller this is a PURE DATA query: nothing is drawn on the user's screen. Visual surfaces are user-initiated only — a jump-list click shows the native taskbar caption, a toolbar-popup click shows the in-page floaty card. showCaption:true opts an AI caller into the caption ONLY when the user asked to have the window identified on screen. Read-only, never owner-gated.\",\"timeoutSeconds\":15},{\"example\":{\"sessionId\":\"wiki-bmv080\",\"view\":\"authed\"},\"hint\":\"Flip a WIKI pup window between the logged-in and public view IN PLACE: every wiki tab reloads with the server-side ?view=public param appended (public) or stripped (authed) — adom/wiki#126 renders the request exactly as a signed-out visitor while the session stays untouched, so there is no relaunch, no cookie wipe, no profile switch (the legacy jar relaunch survives only as a fallback for servers that ignore the param). This is the callback for the per-window taskbar jump-list task (WINDOWS ONLY) — a USER-initiated action. AI threads should NOT call this; pass wikiView:\\\"authed\\\"|\\\"public\\\" on pup_open_window instead.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"view\":\"required \\\"authed\\\"|\\\"public\\\"|\\\"toggle\\\" — toggle flips whatever the window currently shows (the Alt+Shift+V hotkey form)\"},\"longRunning\":false,\"name\":\"pup_wiki_set_view\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Flip a WIKI pup window between the logged-in and public view IN PLACE: every wiki tab reloads with the server-side ?view=public param appended (public) or stripped (authed) — adom/wiki#126 renders the request exactly as a signed-out visitor while the session stays untouched, so there is no relaunch, no cookie wipe, no profile switch (the legacy jar relaunch survives only as a fallback for servers that ignore the param). This is the callback for the per-window taskbar jump-list task (WINDOWS ONLY) — a USER-initiated action. AI threads should NOT call this; pass wikiView:\\\"authed\\\"|\\\"public\\\" on pup_open_window instead.\",\"timeoutSeconds\":45},{\"example\":{\"sessionId\":\"work\",\"url\":\"https://example.com\"},\"hint\":\"Drives the active tab to url and waits for load. Verify with a screenshot before asserting success.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"url\":\"required str\"},\"longRunning\":false,\"name\":\"pup_navigate\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"navigation can race SPA routing — confirm with pup_screenshot\",\"some sites need pup_wait for a selector after navigate\"],\"related\":[\"pup_screenshot\",\"pup_wait\",\"pup_reload\"],\"statusVerb\":null,\"summary\":\"Navigate the active tab to a URL.\",\"timeoutSeconds\":45},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"History back on the active tab.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_back\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[\"pup_forward\",\"pup_navigate\"],\"statusVerb\":null,\"summary\":\"History back.\",\"timeoutSeconds\":20},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"History forward on the active tab.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_forward\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[\"pup_back\",\"pup_navigate\"],\"statusVerb\":null,\"summary\":\"History forward.\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"Paint the Windows taskbar PROGRESS BAR on your window during a LONG multi-stage task (crawling a site, login->search->download loops, batch harvesting datasheets/STEP files) so the user sees work happening at a glance. mode:\\\"indeterminate\\\" (pulsing) to start, mode:\\\"value\\\" with value:0-100 as stages complete, mode:\\\"off\\\" when done or aborted (always clear!). Optional note:\\\"12/40 datasheets\\\" shows on the button hover tooltip. YOUR judgment: a single quick page open does NOT warrant a progress bar. See the pup-progress skill.\",\"input\":{\"mode\":\"\\\"indeterminate\\\" | \\\"value\\\" | \\\"off\\\"\",\"note\":\"optional short stage label for the hover tooltip\",\"sessionId\":\"optional — defaults to your thread's own window\",\"value\":\"optional 0-100 (mode:\\\"value\\\")\"},\"longRunning\":false,\"name\":\"pup_progress\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Paint the Windows taskbar PROGRESS BAR on your window during a LONG multi-stage task (crawling a site, login->search->download loops, batch harvesting datasheets/STEP files) so the user sees work happening at a glance. mode:\\\"indeterminate\\\" (pulsing) to start, mode:\\\"value\\\" with value:0-100 as stages complete, mode:\\\"off\\\" when done or aborted (always clear!). Optional note:\\\"12/40 datasheets\\\" shows on the button hover tooltip. YOUR judgment: a single quick page open does NOT warrant a progress bar. See the pup-progress skill.\",\"timeoutSeconds\":8},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Reloads the active tab.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_reload\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"A page with unsaved changes raises a native \\\"Reload site?\\\" dialog that BLOCKS the window: the reload appears to time out and so does everything else. Answer it with pup_dialog.\"],\"related\":[\"pup_navigate\",\"pup_wait\",\"pup_dialog\"],\"statusVerb\":null,\"summary\":\"Reload the active tab.\",\"timeoutSeconds\":30},{\"example\":{\"selector\":\"button#go\",\"sessionId\":\"work\"},\"hint\":\"Clicks by CSS selector (preferred) or by x,y coords. Selector is more robust across layouts.\",\"input\":{\"button\":\"optional \\\"left\\\"|\\\"right\\\"|\\\"middle\\\"\",\"clickCount\":\"optional int 1-3\",\"domClick\":\"optional bool — dispatch a synthetic element.click() instead of a trusted CDP click; for React controls that ignore trusted clicks\",\"selector\":\"optional str\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"x\":\"optional int\",\"y\":\"optional int\"},\"longRunning\":false,\"name\":\"pup_click\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"selector must match exactly one visible element — verify with pup_evaluate first\",\"coords are viewport-relative; a scrolled element may be off-screen\"],\"related\":[\"pup_type\",\"pup_input_dispatch\",\"pup_screenshot\"],\"statusVerb\":null,\"summary\":\"Click an element (by selector or coords). Selector clicks LOCATE the element once then click by its center coordinates (fast on huge/animated DOMs, where page.click used to hit the 15s wall). Response includes method. If a React toggle/like/heart does NOT change state after a normal click, that control ignores trusted clicks — retry with domClick:true to fire a synthetic element.click().\",\"timeoutSeconds\":20},{\"example\":{\"label\":\"your Google account\",\"reason\":\"clicking your Google account to finish signing into Autodesk\",\"sessionId\":\"adsk\",\"x\":900,\"y\":379},\"hint\":\"RESPECTFUL real-cursor click for a surface pup CDP cannot drive (a NATIVE OS dialog, or a cross-origin FedCM \\\"Sign in with Google\\\" account chooser that rejects every in-page click). Do NOT hand-roll raise+desktop_click for these — use THIS. It: captions the reason + toasts BEFORE touching the screen; foregrounds; then WAITS, detecting if the user alt-tabbed away and holding (captioning \\\"Adom is waiting — click back when ready\\\") until the user is actually on the window; then runs the TIGHT real-cursor hover->click that FedCM accepts (interleaving any screenshot/eval between raise and click makes the click silently no-op); captions each step. Times out as user_not_ready clicking NOTHING if they never return. First take a desktop_screenshot_window of the session to read the target's WINDOW-pixel x,y.\",\"input\":{\"label\":\"required str — WHAT you are clicking (e.g. \\\"your Google account\\\")\",\"maxWaitMs\":\"optional int — how long to wait for the user (default 120000)\",\"reason\":\"required str — WHY you must click (shown to the user as a caption)\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"x\":\"required int — WINDOW-image pixel of the target (from desktop_screenshot_window)\",\"y\":\"required int\"},\"longRunning\":false,\"name\":\"pup_assisted_click\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"RESPECTFUL real-cursor click for a surface pup CDP cannot drive (a NATIVE OS dialog, or a cross-origin FedCM \\\"Sign in with Google\\\" account chooser that rejects every in-page click). Do NOT hand-roll raise+desktop_click for these — use THIS. It: captions the reason + toasts BEFORE touching the screen; foregrounds; then WAITS, detecting if the user alt-tabbed away and holding (captioning \\\"Adom is waiting — click back when ready\\\") until the user is actually on the window; then runs the TIGHT real-cursor hover->click that FedCM accepts (interleaving any screenshot/eval between raise and click makes the click silently no-op); captions each step. Times out as user_not_ready clicking NOTHING if they never return. First take a desktop_screenshot_window of the session to read the target's WINDOW-pixel x,y.\",\"timeoutSeconds\":130},{\"example\":{\"clear\":true,\"selector\":\"#user\",\"sessionId\":\"work\",\"text\":\"adominc1\"},\"hint\":\"Types into the focused or selector-targeted field.\",\"input\":{\"clear\":\"optional bool — empty the field first (replace, not append)\",\"selector\":\"optional str\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"text\":\"required str\"},\"longRunning\":false,\"name\":\"pup_type\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"focus the field first (pup_click the input) or pass selector\",\"does not clear existing text — select-all + delete if you need a clean field\"],\"related\":[\"pup_click\",\"pup_press_key\"],\"statusVerb\":null,\"summary\":\"Type text into a field via real CDP keystrokes (isTrusted). Reads the value back and returns valueLanded — real keystrokes only register in a FOREGROUNDED window, so if valueLanded:false the field stayed empty (the silent no-op): use pup_fill (background-safe) for a non-React input, or pup_login {realKeystrokes:true} for a login form. Pass clear:true to REPLACE instead of appending.\",\"timeoutSeconds\":20},{\"example\":{\"selector\":\"#email\",\"sessionId\":\"work\",\"text\":\"[email protected]\"},\"hint\":\"Set a field's value in the BACKGROUND (no foreground, no keystrokes): writes .value via the native setter and fires input+change so React/Vue/Angular controlled inputs pick it up. The fix for pup_type's silent no-op on a backgrounded window. Reads the value back and returns valueLanded. For React-MASKED password fields that reject programmatic writes, use pup_login {realKeystrokes:true} instead.\",\"input\":{\"selector\":\"required str\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"text\":\"required str\"},\"longRunning\":false,\"name\":\"pup_fill\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Set a field's value in the BACKGROUND (no foreground, no keystrokes): writes .value via the native setter and fires input+change so React/Vue/Angular controlled inputs pick it up. The fix for pup_type's silent no-op on a backgrounded window. Reads the value back and returns valueLanded. For React-MASKED password fields that reject programmatic writes, use pup_login {realKeystrokes:true} instead.\",\"timeoutSeconds\":20},{\"example\":{\"key\":\"a\",\"modifiers\":[\"Control\"],\"sessionId\":\"work\"},\"hint\":\"Presses a key or chord (Enter, Ctrl+A, Tab).\",\"input\":{\"key\":\"required str\",\"modifiers\":\"optional array — any of [\\\"Control\\\",\\\"Shift\\\",\\\"Alt\\\",\\\"Meta\\\"] (aliases ctrl/cmd/command/option accepted); held down around the key press\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_press_key\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"chord syntax is \\\"Ctrl+A\\\" — verify the page has focus on the intended element\"],\"related\":[\"pup_type\",\"pup_input_dispatch\"],\"statusVerb\":null,\"summary\":\"Press a key, optionally with modifier chords held (Ctrl+A, Ctrl+V, Shift+Tab).\",\"timeoutSeconds\":15},{\"example\":{},\"hint\":\"⛔ READ BEFORE USING AD's desktop_click / desktop_type / desktop_press_key ON A PUP WINDOW. Native OS input does NOT target a window — it goes to WHATEVER WINDOW HAS OS FOCUS at that instant. This user runs many AI threads and alt-tabs away from a foregrounded window almost immediately. If you fire native input without warning them, your keystrokes land in THEIR document (this happened: a username was typed into the user's own window). REQUIRED: notify_user toast + desktop_caption FIRST, tell them explicitly \\\"don't type or click until I say done\\\", wait until the window is genuinely foreground, re-verify immediately before EACH event, and caption when done. pup_assisted_click already does all of this — use it. And ALWAYS prefer CDP input (pup_click/pup_type/pup_hover): it needs no foreground and disturbs nobody. A native verb returning ok:true means the event was dispatched to the OS, NOT that it reached your window.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_NATIVE_INPUT_WARNING\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"⛔ READ BEFORE USING AD's desktop_click / desktop_type / desktop_press_key ON A PUP WINDOW. Native OS input does NOT target a window — it goes to WHATEVER WINDOW HAS OS FOCUS at that instant. This user runs many AI threads and alt-tabs away from a foregrounded window almost immediately. If you fire native input without warning them, your keystrokes land in THEIR document (this happened: a username was typed into the user's own window). REQUIRED: notify_user toast + desktop_caption FIRST, tell them explicitly \\\"don't type or click until I say done\\\", wait until the window is genuinely foreground, re-verify immediately before EACH event, and caption when done. pup_assisted_click already does all of this — use it. And ALWAYS prefer CDP input (pup_click/pup_type/pup_hover): it needs no foreground and disturbs nobody. A native verb returning ok:true means the event was dispatched to the OS, NOT that it reached your window.\",\"timeoutSeconds\":0},{\"example\":{\"reset\":true,\"sessionId\":\"work\"},\"hint\":\"Pin the page viewport (CDP device-metrics) to an exact size for deterministic screenshots — OR clear that pin. ⚠ A pin PERSISTS: it survives navigation and hard reload, and while set the window stops tracking OS resizing (a human resizing it sees no reflow, which looks exactly like an app layout bug). ALWAYS clear it when done. Reported as emulatedViewport in pup_status / pup_list_windows.\",\"input\":{\"deviceScaleFactor\":\"optional number (default 1)\",\"height\":\"int — required unless reset\",\"reset\":\"optional bool — CLEAR the override and track the OS window again (width/height not needed)\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"width\":\"int — required unless reset\"},\"longRunning\":false,\"name\":\"pup_set_viewport\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Pin the page viewport (CDP device-metrics) to an exact size for deterministic screenshots — OR clear that pin. ⚠ A pin PERSISTS: it survives navigation and hard reload, and while set the window stops tracking OS resizing (a human resizing it sees no reflow, which looks exactly like an app layout bug). ALWAYS clear it when done. Reported as emulatedViewport in pup_status / pup_list_windows.\",\"timeoutSeconds\":15},{\"example\":{},\"hint\":\"Status/trigger for the toolbar extension, which AUTO-INSTALLS invisibly at every profile launch (transient pipe-launch + CDP Extensions.loadUnpacked; persists in the profile). Running profiles pick it up on their next launch; cold profiles install immediately.\",\"input\":{\"profile\":\"optional, default adom-you\"},\"longRunning\":false,\"name\":\"pup_install_toolbar\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Status/trigger for the toolbar extension, which AUTO-INSTALLS invisibly at every profile launch (transient pipe-launch + CDP Extensions.loadUnpacked; persists in the profile). Running profiles pick it up on their next launch; cold profiles install immediately.\",\"timeoutSeconds\":30},{\"example\":{},\"hint\":\"TEST SEAM: simulate a user click on the floaty pencil (fires the same host click handler a mouse does; the sweep then starts annotate within ~4s). Built for the recurring floaty ralph — assert the annotate overlay appears after calling this.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"tabId\":\"optional tab\"},\"longRunning\":false,\"name\":\"pup_floaty_click\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"TEST SEAM: simulate a user click on the floaty pencil (fires the same host click handler a mouse does; the sweep then starts annotate within ~4s). Built for the recurring floaty ralph — assert the annotate overlay appears after calling this.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"Start the HUMAN annotation overlay on a window's active tab (pen/arrow/box/text toolbar injected in-page; also on every window's taskbar jump list as \\\"Annotate this page\\\"). Two capture modes the user can also flip in the toolbar: \\\"auto\\\" (default) captures the instant the mouse lifts — the one-red-circle case; \\\"multi\\\" accumulates shapes (color swatches: red/blue/yellow one click, more in a flyout) and captures ONCE on Done. Done captures a PNG AND leaves the drawing in the DOM, so the owning thread's next pup_screenshot shows exactly what the user marked — check session.lastAnnotation via pup_list_windows. action:\\\"cancel\\\" removes the overlay.\",\"input\":{\"action\":\"optional \\\"cancel\\\"\",\"mode\":\"optional \\\"auto\\\"|\\\"multi\\\"\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_annotate\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Start the HUMAN annotation overlay on a window's active tab (pen/arrow/box/text toolbar injected in-page; also on every window's taskbar jump list as \\\"Annotate this page\\\"). Two capture modes the user can also flip in the toolbar: \\\"auto\\\" (default) captures the instant the mouse lifts — the one-red-circle case; \\\"multi\\\" accumulates shapes (color swatches: red/blue/yellow one click, more in a flyout) and captures ONCE on Done. Done captures a PNG AND leaves the drawing in the DOM, so the owning thread's next pup_screenshot shows exactly what the user marked — check session.lastAnnotation via pup_list_windows. action:\\\"cancel\\\" removes the overlay.\",\"timeoutSeconds\":15},{\"example\":{},\"hint\":\"Open the LIVE pup management dashboard in its OWN window (its own profile, so its own taskbar icon). Shows every window pup is driving as taskbar button -> window(s) -> tabs with each tab favicon, owning AI thread, foreground/background + the reason given to foreground it, highFps lease, uptime, and WHY each overlay icon was chosen. Live over SSE. Reuses the one window on repeat calls; backgrounded by default like any pup window.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_dashboard\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Open the LIVE pup management dashboard in its OWN window (its own profile, so its own taskbar icon). Shows every window pup is driving as taskbar button -> window(s) -> tabs with each tab favicon, owning AI thread, foreground/background + the reason given to foreground it, highFps lease, uptime, and WHY each overlay icon was chosen. Live over SSE. Reuses the one window on repeat calls; backgrounded by default like any pup window.\",\"timeoutSeconds\":30},{\"example\":{},\"hint\":\"Report pup dependency health (wiki issue #15): depsPresent, selfInstalledThisBoot, lastError. Use this to answer \\\"is pup broken?\\\" without reading spawn logs.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_deps\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Report pup dependency health (wiki issue #15): depsPresent, selfInstalledThisBoot, lastError. Use this to answer \\\"is pup broken?\\\" without reading spawn logs.\",\"timeoutSeconds\":10},{\"example\":{\"selector\":\"#menu\",\"sessionId\":\"work\"},\"hint\":\"Move the pointer over a target WITHOUT clicking (reveals tooltips / hover menus). Glides the visible Adom cursor there too.\",\"input\":{\"intent\":\"optional str — narrated on the cursor label\",\"selector\":\"optional str\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"steps\":\"optional int (default 8)\",\"x\":\"optional int\",\"y\":\"optional int\"},\"longRunning\":false,\"name\":\"pup_hover\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Move the pointer over a target WITHOUT clicking (reveals tooltips / hover menus). Glides the visible Adom cursor there too.\",\"timeoutSeconds\":15},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Maximize (or restore/fullscreen/minimize) a pup window via CDP — no AD desktop verb required. Does NOT foreground it.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"state\":\"optional \\\"maximized\\\"|\\\"normal\\\"|\\\"minimized\\\"|\\\"fullscreen\\\" (default maximized)\"},\"longRunning\":false,\"name\":\"pup_maximize\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Maximize (or restore/fullscreen/minimize) a pup window via CDP — no AD desktop verb required. Does NOT foreground it.\",\"timeoutSeconds\":15},{\"example\":{\"avatarB64\":\"<base64 png>\",\"name\":\"John Lauer\"},\"hint\":\"Set the Adom identity shown in the floating owner chip on every pup window (avatar + name). Chrome's own profile chip cannot take a custom local image (Google sign-in only), so the user's Adom avatar lives here instead. Pass a pre-circle-cropped PNG as base64. Applies to live windows immediately + persists.\",\"input\":{\"avatarB64\":\"optional str — base64 PNG (ideally ~48px, circle-cropped); the leading data: prefix is stripped if present\",\"clear\":\"optional bool — remove the stored avatar + name\",\"enabled\":\"optional bool — turn the whole owner chip on/off\",\"name\":\"optional str — display name shown in the chip tooltip\"},\"longRunning\":false,\"name\":\"pup_set_identity\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Set the Adom identity shown in the floating owner chip on every pup window (avatar + name). Chrome's own profile chip cannot take a custom local image (Google sign-in only), so the user's Adom avatar lives here instead. Pass a pre-circle-cropped PNG as base64. Applies to live windows immediately + persists.\",\"timeoutSeconds\":15},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"PNG of the page. Your primary way to SEE state — call it after navigate/click to confirm.\",\"input\":{\"fullPage\":\"optional bool\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_screenshot\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"default is the viewport; pass fullPage:true for the whole scroll height\"],\"related\":[\"pup_screenshot_full_res\",\"pup_navigate\"],\"statusVerb\":null,\"summary\":\"Screenshot the page (PNG; fullPage optional). NOTE: fullPage only covers DOCUMENT-level scroll — on SPAs that scroll inside a nested container it returns just the viewport + a nestedScroll hint; use pup_screenshot_element or pup_scroll for those.\",\"timeoutSeconds\":30},{\"example\":{\"selector\":\".download-card\",\"sessionId\":\"work\"},\"hint\":\"Screenshot ONE element, resolved by CSS selector OR visible text (pierces shadow DOM), scrolled into view first. The clean way to grab a single card/widget on a component-heavy page. Text matches the TIGHTEST text node — to capture the enclosing CARD, add closest (e.g. {text:\\\"Download…\\\", closest:\\\".download-card\\\"}); with closest, an ambiguous phrase still lands on the real widget (skips prose that has no such ancestor). Returns base64 + filePath like pup_screenshot.\",\"input\":{\"closest\":\"optional selector — climb to the nearest ancestor matching it (the card container)\",\"deep\":\"optional bool — pierce shadow DOM (default true)\",\"padding\":\"optional int px around the element\",\"selector\":\"CSS selector (or use text)\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"text\":\"visible text to match (or use selector)\"},\"longRunning\":false,\"name\":\"pup_screenshot_element\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Screenshot ONE element, resolved by CSS selector OR visible text (pierces shadow DOM), scrolled into view first. The clean way to grab a single card/widget on a component-heavy page. Text matches the TIGHTEST text node — to capture the enclosing CARD, add closest (e.g. {text:\\\"Download…\\\", closest:\\\".download-card\\\"}); with closest, an ambiguous phrase still lands on the real widget (skips prose that has no such ancestor). Returns base64 + filePath like pup_screenshot.\",\"timeoutSeconds\":30},{\"example\":{\"sessionId\":\"work\",\"toText\":\"Download\"},\"hint\":\"Scroll the ACTUAL scrolling element (nearest ancestor whose scrollHeight>clientHeight, NOT just window — window.scrollTo no-ops on nested-scroll SPAs). Scroll by delta {dy,dx} OR to an element {toSelector|toText} (pierces shadow DOM). Returns {scrollElement, scrollTop, scrollHeight, clientHeight} so you can confirm it landed.\",\"input\":{\"behavior\":\"optional auto|smooth\",\"block\":\"optional start|center|end (for scroll-to; default center)\",\"dx\":\"optional int px\",\"dy\":\"optional int px (down+/up-)\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"toSelector\":\"optional CSS selector to scroll to\",\"toText\":\"optional visible text to scroll to\"},\"longRunning\":false,\"name\":\"pup_scroll\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Scroll the ACTUAL scrolling element (nearest ancestor whose scrollHeight>clientHeight, NOT just window — window.scrollTo no-ops on nested-scroll SPAs). Scroll by delta {dy,dx} OR to an element {toSelector|toText} (pierces shadow DOM). Returns {scrollElement, scrollTop, scrollHeight, clientHeight} so you can confirm it landed.\",\"timeoutSeconds\":30},{\"example\":{\"height\":900,\"sessionId\":\"work\",\"width\":1280},\"hint\":\"Set the page viewport (CDP device-metrics) deterministically, independent of the OS window size — fixes a too-small innerWidth so fullPage/element shots render at a known width. width+height required.\",\"input\":{\"deviceScaleFactor\":\"optional number (default 1)\",\"height\":\"required int px\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"width\":\"required int px\"},\"longRunning\":false,\"name\":\"pup_set_viewport\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Set the page viewport (CDP device-metrics) deterministically, independent of the OS window size — fixes a too-small innerWidth so fullPage/element shots render at a known width. width+height required.\",\"timeoutSeconds\":15},{\"example\":{\"expression\":\"document.title\",\"sessionId\":\"work\"},\"hint\":\"Runs JS in the page and returns the result — use it to read DOM state or verify selectors before acting.\",\"input\":{\"expression\":\"required str — aliases accepted: expr, script, js, code\",\"frame\":\"optional str — run inside this iframe instead of the top document\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_evaluate\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"the expression must be serializable JSON in its return value\",\"runs in the page context, not Node\"],\"related\":[\"pup_click\",\"pup_fetch_url\"],\"statusVerb\":null,\"summary\":\"Evaluate JS in the page and return the result — THE verb for reading DOM state / asserting on a page (same handler as pup_eval). Add frame:\\\"<name|url-substring|index>\\\" to run inside an iframe.\",\"timeoutSeconds\":30},{\"example\":{\"sessionId\":\"work\",\"url\":\"https://api.example.com\"},\"hint\":\"Fetches a URL using the tab's live cookies/session — for authed APIs the bare CLI can't reach. Returns bodyBase64.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"url\":\"required str\"},\"longRunning\":false,\"name\":\"pup_fetch_url\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"for session-scoped URLs pass the tabId whose cookies you need\",\"returns base64 — decode it caller-side\"],\"related\":[\"pup_navigate\",\"pup_evaluate\"],\"statusVerb\":null,\"summary\":\"Fetch a URL's content via the browser (cookies/session intact).\",\"timeoutSeconds\":45},{\"example\":{\"selector\":\"button.download\",\"sessionId\":\"work\"},\"hint\":\"Download a file THROUGH THE BROWSER, exactly as the user clicking it would — real session, real cookies, real anti-bot cookies — and Chrome saves it to the Downloads folder. This is the right verb for vendor files (datasheets, KiCad/Altium libraries, STEP 3D models) that a server-side fetch/curl can never get past the site's bot wall. Pass selector to click the actual download button (authentic), or url to force-download via an in-page a[download]. Confirms completion via Chrome's download events and returns the ACTUAL saved path + byte count + file magic. For a gated file, log in on the window first (pup_login).\",\"input\":{\"saveAs\":\"optional str — filename override\",\"saveDir\":\"optional str — default the user's Downloads folder\",\"selector\":\"optional str — the real download control to click\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"url\":\"optional str — download this URL via an in-page a[download] click\"},\"longRunning\":false,\"name\":\"pup_download\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Download a file THROUGH THE BROWSER, exactly as the user clicking it would — real session, real cookies, real anti-bot cookies — and Chrome saves it to the Downloads folder. This is the right verb for vendor files (datasheets, KiCad/Altium libraries, STEP 3D models) that a server-side fetch/curl can never get past the site's bot wall. Pass selector to click the actual download button (authentic), or url to force-download via an in-page a[download]. Confirms completion via Chrome's download events and returns the ACTUAL saved path + byte count + file magic. For a gated file, log in on the window first (pup_login).\",\"timeoutSeconds\":100},{\"example\":{\"sessionId\":\"work\",\"type\":\"mousePressed\",\"x\":100,\"y\":200},\"hint\":\"Low-level CDP mouse/keyboard input at coords — beats some overlays/iframes that swallow synthetic clicks.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"type\":\"required str\",\"x\":\"optional int\",\"y\":\"optional int\"},\"longRunning\":false,\"name\":\"pup_input_dispatch\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"coords are viewport pixels\",\"last-resort when pup_click can't reach the element — still cannot pass Cloudflare interactive challenges\"],\"related\":[\"pup_click\",\"pup_press_key\"],\"statusVerb\":null,\"summary\":\"Low-level input (mouse/keyboard) at coords — beats some overlays.\",\"timeoutSeconds\":20},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Starts video recording of the page for this session.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_record_start\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"one recording per session — stop the current one before starting another\"],\"related\":[\"pup_record_stop\",\"pup_record_status\"],\"statusVerb\":null,\"summary\":\"Start recording the page (video).\",\"timeoutSeconds\":20},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Stops recording and returns the saved file path.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_record_stop\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"no-op if nothing is recording for this session\"],\"related\":[\"pup_record_start\",\"pup_record_list\"],\"statusVerb\":null,\"summary\":\"Stop recording; returns the saved file.\",\"timeoutSeconds\":30},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Whether a recording is active for the session.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_record_status\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[\"pup_record_start\",\"pup_record_stop\"],\"statusVerb\":null,\"summary\":\"Recording status for a session.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"Lists saved page recordings.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_record_list\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[\"pup_record_start\"],\"statusVerb\":null,\"summary\":\"List recordings.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"Open pup's Chrome screen-share recorder HUD (WebM; consent = the visible HUD). Canonical name (pup-bridge#94).\",\"input\":{\"reason\":\"str (required)\"},\"longRunning\":false,\"name\":\"pup_recorder_open\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Open pup's Chrome screen-share recorder HUD (WebM; consent = the visible HUD). Canonical name (pup-bridge#94).\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"Start a whole-screen recording through Chrome screen-share (WebM VP9, system audio + mic). Canonical name; for a background no-browser MP4 of one window use ab-core desktop_record_window_start.\",\"input\":{\"audio\":\"bool\",\"confirmDesktopNotTabRecording\":\"true\",\"fps\":\"int\",\"maxDurationMs\":\"int\",\"reason\":\"str (required)\"},\"longRunning\":false,\"name\":\"pup_screen_record_start\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Start a whole-screen recording through Chrome screen-share (WebM VP9, system audio + mic). Canonical name; for a background no-browser MP4 of one window use ab-core desktop_record_window_start.\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"Stop the Chrome screen recording; returns the .webm path.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_screen_record_stop\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Stop the Chrome screen recording; returns the .webm path.\",\"timeoutSeconds\":30},{\"example\":{},\"hint\":\"Status of the Chrome screen recorder + any active clip.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_screen_record_status\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Status of the Chrome screen recorder + any active clip.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"List completed Chrome screen recordings on disk.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_screen_record_list\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"List completed Chrome screen recordings on disk.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"Close the Chrome screen-recorder HUD (auto-stops a clip).\",\"input\":{},\"longRunning\":false,\"name\":\"pup_recorder_close\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Close the Chrome screen-recorder HUD (auto-stops a clip).\",\"timeoutSeconds\":15},{\"example\":{},\"hint\":\"Opens the desktop screen-recorder UI window. OWNERSHIP: the desktop_ namespace is ab-core's; pup serves these on ab's behalf only until ab-core's native whole-desktop recorder lands (adom-bridge#143), then they leave pup. Tab recording (pup_record_*) is pup's own.\",\"input\":{},\"longRunning\":false,\"name\":\"desktop_recorder_open\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[\"desktop_record_start\",\"desktop_recorder_close\"],\"statusVerb\":null,\"summary\":\"ALIAS of pup_recorder_open (routes to ab-core once its native recorder lands, adom-bridge#143).\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"Starts a full desktop screen recording (served by pup for ab-core until adom-bridge#143 lands; needs ffmpeg on the box for the duration header).\",\"input\":{\"outPath\":\"optional str\"},\"longRunning\":false,\"name\":\"desktop_record_start\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"only one desktop recording at a time\"],\"related\":[\"desktop_record_stop\",\"desktop_record_status\"],\"statusVerb\":null,\"summary\":\"ALIAS of pup_screen_record_start (routes to ab-core once its native recorder lands, adom-bridge#143).\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"Stops the desktop recording and returns the file.\",\"input\":{},\"longRunning\":false,\"name\":\"desktop_record_stop\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[\"desktop_record_start\",\"desktop_record_list\"],\"statusVerb\":null,\"summary\":\"ALIAS of pup_screen_record_stop.\",\"timeoutSeconds\":30},{\"example\":{},\"hint\":\"Cold-start readiness probe: {ready, chromeForTestingInstalled, installing, installProgressPct}. On a fresh PC, poll this until ready:true before pup_open_window — the bridge auto-installs Chrome for Testing on its own.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_readiness\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"ready:false with installing:true just means Chrome for Testing is still downloading — wait + poll, do NOT treat it as an error\",\"installPhase:\\\"failed\\\" → surface lastError to the user (usually network/proxy blocking the download, or low disk)\"],\"related\":[\"pup_prewarm\",\"pup_open_window\"],\"statusVerb\":null,\"summary\":\"Readiness + which browser pup will drive (installed Chrome/Edge, or cached Chrome for Testing) + the full candidate list and current default. READ-ONLY; never downloads.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"Installs Chrome for Testing (the browser pup drives) WITHOUT opening a window — the warm-before-first-use path. Returns fast; poll pup_readiness for completion.\",\"input\":{\"setDefault\":\"optional bool (default true) — pin CfT as the default\",\"wait\":\"optional bool — block until installed\"},\"longRunning\":false,\"name\":\"pup_prewarm\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[\"the ~150 MB download needs network access to storage.googleapis.com\",\"does not open a window — call pup_open_window once readiness reports ready:true\"],\"related\":[\"pup_readiness\",\"pup_open_window\"],\"statusVerb\":null,\"summary\":\"Install Chrome for Testing WITHOUT opening a window, and pin it as the default. Use when you specifically want CfT rather than the machine's installed Chrome/Edge.\",\"timeoutSeconds\":240},{\"example\":{},\"hint\":\"Pin (or clear) the browser pup drives by default: chrome | edge | cft | auto (or an explicit executablePath). \\\"cft\\\" fetches Chrome for Testing then pins it. With {browser:\\\"chrome\\\", install:true} it DOWNLOADS & INSTALLS real Google Chrome on an Edge-only box, then pins it — SILENT on a normal PC; on a locked-down box (VM/managed device) it needs a Windows approval, so the bridge pops a native \\\"click YES on the UAC\\\" notification and, if it expires, re-notifies with a one-tap \\\"Approve now\\\" (all autonomous — no AI turn). Poll pup_readiness.chromeStablePhase: installing → awaiting_uac → ready. Persists across restarts; launch still spawn-verifies + falls back.\",\"input\":{\"browser\":\"\\\"chrome\\\" | \\\"edge\\\" | \\\"cft\\\" | \\\"auto\\\"\",\"elevate\":\"optional \\\"auto\\\"(default)|true|false — auto: quiet install, prompt only if it needs admin; false: never prompt; true: go straight to the prompt\",\"executablePath\":\"optional — pin an exact browser binary\",\"install\":\"optional bool — with browser:\\\"chrome\\\", install real Chrome if missing\"},\"longRunning\":false,\"name\":\"pup_use\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Pin (or clear) the browser pup drives by default: chrome | edge | cft | auto (or an explicit executablePath). \\\"cft\\\" fetches Chrome for Testing then pins it. With {browser:\\\"chrome\\\", install:true} it DOWNLOADS & INSTALLS real Google Chrome on an Edge-only box, then pins it — SILENT on a normal PC; on a locked-down box (VM/managed device) it needs a Windows approval, so the bridge pops a native \\\"click YES on the UAC\\\" notification and, if it expires, re-notifies with a one-tap \\\"Approve now\\\" (all autonomous — no AI turn). Poll pup_readiness.chromeStablePhase: installing → awaiting_uac → ready. Persists across restarts; launch still spawn-verifies + falls back.\",\"timeoutSeconds\":240},{\"example\":{},\"hint\":\"Send a pup window to the BACKGROUND (behind the user's windows) without stealing focus — still fully drivable. The default for open; use this to re-hide a window you foregrounded.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_lower_os_window\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Send a pup window to the BACKGROUND (behind the user's windows) without stealing focus — still fully drivable. The default for open; use this to re-hide a window you foregrounded.\",\"timeoutSeconds\":15},{\"example\":{\"foregroundReason\":\"user said \\\"show me the wiki page\\\"\"},\"hint\":\"Bring a pup window to the FOREGROUND (user's screen). GATED (v1.8.70): REFUSED with foreground_reason_required unless you pass foregroundReason — a quote/paraphrase of what the user said that justifies it (min 10 chars; logged, recorded in lastAgentUpdate, auditable). Allowed ONLY when the user EXPLICITLY must SEE it (a demo, recording, \\\"show me\\\"). It STEALS focus — to just signal \\\"I updated this window\\\", use pup_alert_window (or the auto-flash), NOT raise. After the show-me: pup_lower_os_window to return it to the background. Alias: pup_focus_window. IMPORTANT: if you are foregrounding in order to CLICK a native dialog or a cross-origin FedCM/Google account chooser, do NOT raise-then-click yourself — use pup_assisted_click, which waits for the user to actually be on the window (alt-tab aware) and narrates via captions, so you never act while they are not ready.\",\"input\":{\"foregroundReason\":\"REQUIRED — why the user asked to see this window\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_raise_os_window\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Bring a pup window to the FOREGROUND (user's screen). GATED (v1.8.70): REFUSED with foreground_reason_required unless you pass foregroundReason — a quote/paraphrase of what the user said that justifies it (min 10 chars; logged, recorded in lastAgentUpdate, auditable). Allowed ONLY when the user EXPLICITLY must SEE it (a demo, recording, \\\"show me\\\"). It STEALS focus — to just signal \\\"I updated this window\\\", use pup_alert_window (or the auto-flash), NOT raise. After the show-me: pup_lower_os_window to return it to the background. Alias: pup_focus_window. IMPORTANT: if you are foregrounding in order to CLICK a native dialog or a cross-origin FedCM/Google account chooser, do NOT raise-then-click yourself — use pup_assisted_click, which waits for the user to actually be on the window (alt-tab aware) and narrates via captions, so you never act while they are not ready.\",\"timeoutSeconds\":15},{\"example\":{\"sessionId\":\"work\",\"submit\":true,\"submitReason\":\"confirmed the tab is on the real vendor domain I intended to sign into\"},\"hint\":\"Fill (and optionally submit) an HTML login form in the CURRENT tab, in the BACKGROUND — no Chrome autofill dropdown, no foregrounding, React/Vue-safe. Creds from the keychain vault (matched on the tab URL; captured automatically as you log in, or stored via credential_set / save:true) or passed explicitly. Passwords are NEVER echoed back. Vault-matched pages AUTO-FILL on load (_autoLogin on the response). SUBMIT IS REASON-GATED: submit:true requires submitReason AND makes you confirm the live domain (the refusal regurgitates the exact host so a lookalike/phishing site is caught before the secret is sent). pup_configure {autoLogin:\\\"off\\\"} disables auto-fill; {captureLogins:\\\"off\\\"} stops auto-capture.\",\"input\":{\"host\":\"optional str — override the vault host key when saving\",\"password\":\"optional str — with username, fills these instead of the vault\",\"realKeystrokes\":\"optional bool — type with REAL key events instead of a background .value-set. Needed for React-controlled MASKED fields (Gusto/Keycloak SSO) that ignore .value and would submit an empty password. It briefly FOREGROUNDS the window (real keystrokes only register on-screen). Use when a normal fill returned filledPassword:false / reactMaskedFieldSuspected, or when the login-recipe for the site says so.\",\"save\":\"optional bool — with explicit creds, store them (OS keychain) so next time is automatic\",\"sessionId\":\"optional str — omit to target the window your own thread owns\",\"submit\":\"optional bool — submit after filling; REQUIRES submitReason\",\"submitReason\":\"required WITH submit:true — why you are confident the CURRENT domain is the correct, intended site to send these credentials to (min 10 chars; the refusal shows you the live host to confirm; logged, auditable)\",\"username\":\"optional str\"},\"longRunning\":false,\"name\":\"pup_login\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Fill (and optionally submit) an HTML login form in the CURRENT tab, in the BACKGROUND — no Chrome autofill dropdown, no foregrounding, React/Vue-safe. Creds from the keychain vault (matched on the tab URL; captured automatically as you log in, or stored via credential_set / save:true) or passed explicitly. Passwords are NEVER echoed back. Vault-matched pages AUTO-FILL on load (_autoLogin on the response). SUBMIT IS REASON-GATED: submit:true requires submitReason AND makes you confirm the live domain (the refusal regurgitates the exact host so a lookalike/phishing site is caught before the secret is sent). pup_configure {autoLogin:\\\"off\\\"} disables auto-fill; {captureLogins:\\\"off\\\"} stops auto-capture.\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"List saved logins (host + username only; passwords are in the OS keychain and NEVER returned). pup captures these automatically as you sign into sites and auto-fills them in the background on return visits.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_credentials\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"List saved logins (host + username only; passwords are in the OS keychain and NEVER returned). pup captures these automatically as you sign into sites and auto-fills them in the background on return visits.\",\"timeoutSeconds\":10},{\"example\":{\"host\":\"github.com\",\"reason\":\"signing into GitHub in my own browser to open a PR for the user\"},\"hint\":\"Reveal ONE saved login (username + password) to a LOCAL caller on the desktop, gated by a sticky consent toast the user must click. One host per call, never bulk. A relayed (cloud container) call is refused with relay_forbidden: from a cloud thread use pup_login instead, which signs the site in inside a pup window without the secret ever leaving the vault. The secret is returned ONCE and must never be logged or echoed.\",\"input\":{\"host\":\"required str — the site, e.g. \\\"github.com\\\"\",\"reason\":\"required str (min 10 chars) — shown to the user on the consent toast; say what you will do with it\"},\"longRunning\":false,\"name\":\"pup_credential_reveal\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Reveal ONE saved login (username + password) to a LOCAL caller on the desktop, gated by a sticky consent toast the user must click. One host per call, never bulk. A relayed (cloud container) call is refused with relay_forbidden: from a cloud thread use pup_login instead, which signs the site in inside a pup window without the secret ever leaving the vault. The secret is returned ONCE and must never be logged or echoed.\",\"timeoutSeconds\":130},{\"example\":{},\"hint\":\"Store a payment card in the OS-keychain card vault under a nickname. Ask the USER for the details — never harvest them from a page. Validates Luhn + expiry + cvv. No verb ever returns the number or CVV afterward.\",\"input\":{\"cvv\":\"required 3-4 digits\",\"expiry\":\"required MM/YY\",\"name\":\"optional cardholder name\",\"nickname\":\"required str, e.g. \\\"adom-amex\\\"\",\"number\":\"required str\"},\"longRunning\":false,\"name\":\"pup_card_set\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Store a payment card in the OS-keychain card vault under a nickname. Ask the USER for the details — never harvest them from a page. Validates Luhn + expiry + cvv. No verb ever returns the number or CVV afterward.\",\"timeoutSeconds\":15},{\"example\":{},\"hint\":\"List saved payment cards: nickname, brand, last4, expiry, cardholder only. The number and CVV never leave the keychain.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_cards\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"List saved payment cards: nickname, brand, last4, expiry, cardholder only. The number and CVV never leave the keychain.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"Remove a saved card from the keychain + index by nickname.\",\"input\":{\"nickname\":\"required str\"},\"longRunning\":false,\"name\":\"pup_card_delete\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Remove a saved card from the keychain + index by nickname.\",\"timeoutSeconds\":10},{\"example\":{\"amount\":\"$350\",\"merchant\":\"venturedallas.com\",\"nickname\":\"adom-amex\"},\"hint\":\"Fill a saved card into the checkout page of a pup window WITHOUT the digits ever reaching you: pup types them into the card fields (walking payment-processor iframes like Stripe) and returns booleans. EVERY fill is gated by a desktop approval toast naming merchant, amount and last4 — the user authorizes the specific charge in the moment. Pass merchant+amount so the toast is honest. Allowed from cloud threads (the human click is the gate). After ok:true, screenshot to verify, then submit.\",\"input\":{\"amount\":\"recommended str, e.g. \\\"$350\\\"\",\"merchant\":\"recommended str — shown on the approval toast\",\"nickname\":\"required str\",\"window\":\"optional (defaults to your thread's window)\"},\"longRunning\":false,\"name\":\"pup_fill_card\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Fill a saved card into the checkout page of a pup window WITHOUT the digits ever reaching you: pup types them into the card fields (walking payment-processor iframes like Stripe) and returns booleans. EVERY fill is gated by a desktop approval toast naming merchant, amount and last4 — the user authorizes the specific charge in the moment. Pass merchant+amount so the toast is honest. Allowed from cloud threads (the human click is the gate). After ok:true, screenshot to verify, then submit.\",\"timeoutSeconds\":130},{\"example\":{\"hostFilter\":[\"snapeda\",\"ultralibrarian\",\"digikey\"]},\"hint\":\"Seed pup's vault from the user's OWN saved Chrome/Edge/Brave passwords, so pup can sign in as them on sites they already use (vendor CAD portals, etc). Runs the SYSTEM-elevated decrypt LOCALLY — the user approves ONE consent dialog + ONE Windows UAC prompt on the desktop (a cloud/relay caller cannot do this; only pup, a local bridge, can ask). Merges the identity-tagged rows into the keychain vault and DROPS the plaintext. Returns COUNTS ONLY. hostFilter narrows the import to matching hosts (surgical, e.g. [\\\"snapeda\\\",\\\"digikey\\\"]); omit to import everything saved. Pair with pup_import_scan (read-only preview of how many logins exist).\",\"input\":{\"browsers\":\"optional str[] subset of [\\\"chrome\\\",\\\"edge\\\",\\\"brave\\\"] (default: all found)\",\"hostFilter\":\"optional str or str[] — only import logins whose host contains one of these (surgical import)\"},\"longRunning\":false,\"name\":\"pup_import_browser_logins\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Seed pup's vault from the user's OWN saved Chrome/Edge/Brave passwords, so pup can sign in as them on sites they already use (vendor CAD portals, etc). Runs the SYSTEM-elevated decrypt LOCALLY — the user approves ONE consent dialog + ONE Windows UAC prompt on the desktop (a cloud/relay caller cannot do this; only pup, a local bridge, can ask). Merges the identity-tagged rows into the keychain vault and DROPS the plaintext. Returns COUNTS ONLY. hostFilter narrows the import to matching hosts (surgical, e.g. [\\\"snapeda\\\",\\\"digikey\\\"]); omit to import everything saved. Pair with pup_import_scan (read-only preview of how many logins exist).\",\"timeoutSeconds\":190},{\"example\":{\"dryRun\":true},\"hint\":\"Delete LEAKED isolated profile directories — the iso-* throwaway jars minted by isolated:true opens (and by wikiView:public before 2.0.132, when the public view moved to the server-side ?view=public param) whose window is long gone (they used to pile up, 100s per machine). Only removes an iso-* dir that no live session or session file owns, that no Chrome is holding, and that is >15 min old; durable jars (adom-you, named profiles) are NEVER touched. Runs automatically every 15 min too. dryRun:true previews the list without deleting.\",\"input\":{\"dryRun\":\"optional bool — preview which iso-* profiles would be removed, delete nothing\"},\"longRunning\":false,\"name\":\"pup_reap_profiles\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Delete LEAKED isolated profile directories — the iso-* throwaway jars minted by isolated:true opens (and by wikiView:public before 2.0.132, when the public view moved to the server-side ?view=public param) whose window is long gone (they used to pile up, 100s per machine). Only removes an iso-* dir that no live session or session file owns, that no Chrome is holding, and that is >15 min old; durable jars (adom-you, named profiles) are NEVER touched. Runs automatically every 15 min too. dryRun:true previews the list without deleting.\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"MOVE this pup window's page into the user's Hydrogen workspace: the active tab's URL is handed to Hydrogen (ah) on this machine via its Browser Picker (webview by default, honoring the user's per-domain choice), then the pup window closes — its owner initiated the move. keepWindow:true keeps the pup window open too. Needs Hydrogen running locally (hydrogen_unreachable otherwise; the window is left untouched on failure). Cloud Hydrogen (hc) is not yet supported.\",\"input\":{\"keepWindow\":\"optional bool — hand the URL over but keep the pup window open\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_move_to_workspace\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"MOVE this pup window's page into the user's Hydrogen workspace: the active tab's URL is handed to Hydrogen (ah) on this machine via its Browser Picker (webview by default, honoring the user's per-domain choice), then the pup window closes — its owner initiated the move. keepWindow:true keeps the pup window open too. Needs Hydrogen running locally (hydrogen_unreachable otherwise; the window is left untouched on failure). Cloud Hydrogen (hc) is not yet supported.\",\"timeoutSeconds\":25},{\"example\":{\"dryRun\":true},\"hint\":\"DESTRUCTIVE — cleanly remove pup's WHOLE footprint from this machine: the HKCU AppUserModelId Adom.Pup registry keys, all staged extensions, ALL pup profiles + sessions, the OS-keychain credential vault, pup-settings.json, the badge-debug temp dir, and the jump-list launcher. ALWAYS preview first with dryRun:true (removes nothing, returns the plan). To actually remove, pass confirm:\\\"uninstall\\\". keepCredentials:true preserves the saved-login vault; keepProfiles:true preserves profiles/sessions. Chrome-for-Testing + firewall rules are SHARED and left alone unless removeChrome:true / removeFirewallRules:true. Closes every window + quits every browser first to release profile locks. (The bridge itself is managed by Adom Bridge — remove pup from Bridge to stop it re-seeding.)\",\"input\":{\"confirm\":\"required str \\\"uninstall\\\" to actually remove\",\"dryRun\":\"optional bool — preview the removal plan without removing anything (do this first)\",\"keepCredentials\":\"optional bool — keep the saved-login vault\",\"keepProfiles\":\"optional bool — keep pup profiles + sessions\",\"removeChrome\":\"optional bool — also delete the Chrome-for-Testing install (shared; default keep)\",\"removeFirewallRules\":\"optional bool — also remove the CfT firewall rules (needs admin)\"},\"longRunning\":false,\"name\":\"pup_uninstall\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"DESTRUCTIVE — cleanly remove pup's WHOLE footprint from this machine: the HKCU AppUserModelId Adom.Pup registry keys, all staged extensions, ALL pup profiles + sessions, the OS-keychain credential vault, pup-settings.json, the badge-debug temp dir, and the jump-list launcher. ALWAYS preview first with dryRun:true (removes nothing, returns the plan). To actually remove, pass confirm:\\\"uninstall\\\". keepCredentials:true preserves the saved-login vault; keepProfiles:true preserves profiles/sessions. Chrome-for-Testing + firewall rules are SHARED and left alone unless removeChrome:true / removeFirewallRules:true. Closes every window + quits every browser first to release profile locks. (The bridge itself is managed by Adom Bridge — remove pup from Bridge to stop it re-seeding.)\",\"timeoutSeconds\":60},{\"example\":{},\"hint\":\"Nudge the user about a pup window WITHOUT stealing focus — on Windows it flashes the taskbar button; on macOS (no taskbar, and no API to bounce another app's Dock tile) it unhides the window at its z-position and posts an AD toast whose click focuses it. Same contract on both, so call it identically; just never tell a Mac user to look for a flashing icon. NOTE (v1.8.23): mutating verbs already AUTO-FLASH (debounced, one per ~5s burst per window) so the user always knows the agent touched a window — use this for an explicit end-of-task \\\"it's ready\\\" nudge on top of that. STRONGLY prefer this (or the auto-flash) over pup_raise_os_window, which steals focus and can leak a mid-typed keystroke into the page.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"stop\":\"optional bool — CLEAR the highlight instead of flashing\"},\"longRunning\":false,\"name\":\"pup_alert_window\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Nudge the user about a pup window WITHOUT stealing focus — on Windows it flashes the taskbar button; on macOS (no taskbar, and no API to bounce another app's Dock tile) it unhides the window at its z-position and posts an AD toast whose click focuses it. Same contract on both, so call it identically; just never tell a Mac user to look for a flashing icon. NOTE (v1.8.23): mutating verbs already AUTO-FLASH (debounced, one per ~5s burst per window) so the user always knows the agent touched a window — use this for an explicit end-of-task \\\"it's ready\\\" nudge on top of that. STRONGLY prefer this (or the auto-flash) over pup_raise_os_window, which steals focus and can leak a mid-typed keystroke into the page.\",\"timeoutSeconds\":15},{\"example\":{\"html\":\"<h1>Café</h1>\",\"sessionId\":\"work\"},\"hint\":\"Render a local HTML string in the tab via page.setContent — UTF-8-correct (a data: URL mojibakes accented chars without an explicit charset). Great for previewing generated markup without a temp file. Auto-flashes the window.\",\"input\":{\"html\":\"required HTML string\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"silent\":\"optional bool — suppress the auto-flash\",\"updateNote\":\"optional note for lastAgentUpdate\",\"waitUntil\":\"optional (domcontentloaded default)\"},\"longRunning\":false,\"name\":\"pup_render_html\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Render a local HTML string in the tab via page.setContent — UTF-8-correct (a data: URL mojibakes accented chars without an explicit charset). Great for previewing generated markup without a temp file. Auto-flashes the window.\",\"timeoutSeconds\":30},{\"example\":{},\"hint\":\"List all open pup sessions + their tabs (NOT a readiness check — use pup_readiness for that).\",\"input\":{},\"longRunning\":false,\"name\":\"pup_status\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"List all open pup sessions + their tabs (NOT a readiness check — use pup_readiness for that).\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"List every open session/window with its tabs.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_list_windows\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"List every open session/window with its tabs.\",\"timeoutSeconds\":10},{\"example\":{\"expr\":\"document.querySelector(\\\"#userId\\\").value\",\"frame\":\"logonbox\",\"sessionId\":\"work\"},\"hint\":\"pup_eval accepts frame:\\\"<name|url-substring|index>\\\" to run inside an IFRAME (login forms usually live in one). Cross-origin frames work. Omit for the top document; a bad value returns frame_not_found WITH the list of frames in the tab.\",\"input\":{\"expr\":\"required str\",\"frame\":\"optional str\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_eval_frame_note\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"pup_eval accepts frame:\\\"<name|url-substring|index>\\\" to run inside an IFRAME (login forms usually live in one). Cross-origin frames work. Omit for the top document; a bad value returns frame_not_found WITH the list of frames in the tab.\",\"timeoutSeconds\":20},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Make a session the active one (for verbs that default to active).\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_switch_window\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Make a session the active one (for verbs that default to active).\",\"timeoutSeconds\":10},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"List the tabs in a session.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_list_tabs\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"List the tabs in a session.\",\"timeoutSeconds\":10},{\"example\":{\"sessionId\":\"work\",\"tabId\":\"tab-2\"},\"hint\":\"Activate a tab WITHIN its session/window (idempotent — safe to call when the tab is already active). Does NOT raise a background window to the user's screen: the tab becomes the window's visible tab wherever the window is, and the taskbar auto-flash tells the user something changed. Also self-heals the window (re-park if a bug ever stranded it off-screen) and refreshes the Adom taskbar badge — good citizenship for long-lived shared windows.\",\"input\":{\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"silent\":\"optional bool\",\"tabId\":\"required str\",\"updateNote\":\"optional str\"},\"longRunning\":false,\"name\":\"pup_switch_tab\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Activate a tab WITHIN its session/window (idempotent — safe to call when the tab is already active). Does NOT raise a background window to the user's screen: the tab becomes the window's visible tab wherever the window is, and the taskbar auto-flash tells the user something changed. Also self-heals the window (re-park if a bug ever stranded it off-screen) and refreshes the Adom taskbar badge — good citizenship for long-lived shared windows.\",\"timeoutSeconds\":10},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"FULL-resolution page screenshot (NOT downscaled — for saving to disk, NOT for Read: it can exceed Claude's image limit). Use pup_screenshot for AI-readable shots.\",\"input\":{\"fullPage\":\"optional bool\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_screenshot_full_res\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"FULL-resolution page screenshot (NOT downscaled — for saving to disk, NOT for Read: it can exceed Claude's image limit). Use pup_screenshot for AI-readable shots.\",\"timeoutSeconds\":30},{\"example\":{\"sessionId\":\"work\"},\"hint\":\"Console errors + failed network requests for a session/tab (clears by default).\",\"input\":{\"clear\":\"optional bool (default true)\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\",\"tabId\":\"optional str\"},\"longRunning\":false,\"name\":\"pup_errors\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Console errors + failed network requests for a session/tab (clears by default).\",\"timeoutSeconds\":10},{\"example\":{\"ms\":500,\"sessionId\":\"work\"},\"hint\":\"Wait N ms (or for a selector) before the next step.\",\"input\":{\"ms\":\"optional int\",\"selector\":\"optional str\",\"sessionId\":\"optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)\"},\"longRunning\":false,\"name\":\"pup_wait\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Wait N ms (or for a selector) before the next step.\",\"timeoutSeconds\":60},{\"example\":{},\"hint\":\"Recover orphaned sessions: reconnect dropped CDP sockets + rebuild sessions from window titles. Pass adoptOrphans:true to also adopt untagged tabs.\",\"input\":{\"adoptOrphans\":\"optional bool\"},\"longRunning\":false,\"name\":\"pup_rescan\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Recover orphaned sessions: reconnect dropped CDP sockets + rebuild sessions from window titles. Pass adoptOrphans:true to also adopt untagged tabs.\",\"timeoutSeconds\":30},{\"example\":{},\"hint\":\"Close ALL pup sessions + windows at once (destructive). NOTE: `{}` here does NOT mean \\\"the active session\\\" the way it does on other session-scoped verbs — with no args this closes EVERY window, across every AI thread on the machine, with no confirmation. To close ONE window use pup_close_window {sessionId}. Pass {sessionId} here only if you genuinely mean that one session.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_close\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Close ALL pup sessions + windows at once (destructive). NOTE: `{}` here does NOT mean \\\"the active session\\\" the way it does on other session-scoped verbs — with no args this closes EVERY window, across every AI thread on the machine, with no confirmation. To close ONE window use pup_close_window {sessionId}. Pass {sessionId} here only if you genuinely mean that one session.\",\"timeoutSeconds\":20},{\"example\":{},\"hint\":\"ALIAS of pup_screen_record_status.\",\"input\":{},\"longRunning\":false,\"name\":\"desktop_record_status\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"ALIAS of pup_screen_record_status.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"ALIAS of pup_screen_record_list.\",\"input\":{},\"longRunning\":false,\"name\":\"desktop_record_list\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"ALIAS of pup_screen_record_list.\",\"timeoutSeconds\":10},{\"example\":{},\"hint\":\"ALIAS of pup_recorder_close.\",\"input\":{},\"longRunning\":false,\"name\":\"desktop_recorder_close\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"ALIAS of pup_recorder_close.\",\"timeoutSeconds\":15},{\"example\":{\"taskbarGrouping\":\"grouped\"},\"hint\":\"Get/set user-facing pup preferences (persisted across bridge updates). taskbarGrouping: \\\"split\\\" (default — one taskbar button PER WINDOW, each badged with its own tab count; best for telling AI threads apart) | \\\"grouped\\\" (all pup windows stack under ONE \\\"Adom Pup\\\" button, badge shows window count; tidy taskbar). Applies to live windows immediately. Ask the USER which they prefer before changing it — this is their taskbar. WINDOWS ONLY: macOS has no taskbar, so the setting is stored but INERT there; the reply carries platform + taskbarSupported so branch on those, not on this text.\",\"input\":{\"autoLogin\":\"optional \\\"on\\\"|\\\"off\\\" — auto-fill a vault-matched login form on page load (fill only, never submits), on by default\",\"overlaySize\":\"optional \\\"50\\\"|\\\"100\\\" — how big the favicon badge is drawn on the taskbar button. \\\"50\\\" (the DEFAULT) draws it at half size so it stays clear of the thread tile's bottom line of text; \\\"100\\\" is the older, larger badge\",\"reportIssues\":\"optional \\\"on\\\"|\\\"off\\\" — pup's bug-report invitation (_reportIssues), on by default\",\"taskbarActivity\":\"optional \\\"progress\\\"|\\\"flash\\\"|\\\"off\\\" — how pup signals it is working on a window, on that window's taskbar button: a determinate progress bar sized to the operation's running-average time (default), the old orange flash, or nothing. Replaces the former openFlash/autoFlash/agentActivity toggles.\",\"taskbarGrouping\":\"optional \\\"split\\\"|\\\"grouped\\\"\"},\"longRunning\":false,\"name\":\"pup_configure\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[],\"statusVerb\":null,\"summary\":\"Get/set user-facing pup preferences (persisted across bridge updates). taskbarGrouping: \\\"split\\\" (default — one taskbar button PER WINDOW, each badged with its own tab count; best for telling AI threads apart) | \\\"grouped\\\" (all pup windows stack under ONE \\\"Adom Pup\\\" button, badge shows window count; tidy taskbar). Applies to live windows immediately. Ask the USER which they prefer before changing it — this is their taskbar. WINDOWS ONLY: macOS has no taskbar, so the setting is stored but INERT there; the reply carries platform + taskbarSupported so branch on those, not on this text.\",\"timeoutSeconds\":15},{\"example\":{},\"hint\":\"This list — the bridge's verbs + schemas + hints, for AD's Verbs tab. Read it once to learn the surface.\",\"input\":{},\"longRunning\":false,\"name\":\"pup_describe\",\"output\":{\"success\":\"bool\"},\"pitfalls\":[],\"related\":[\"pup_status\"],\"statusVerb\":null,\"summary\":\"This list — the bridge's verbs + schemas, for AD's Verbs tab.\",\"timeoutSeconds\":10}]}",
"progressContract": {
"activeKey": "active",
"blockedByPhases": [
"consent",
"dialog"
],
"blockedOnUser": {
"errorCode": "blocked_on_user",
"inVerbWaitSec": 45,
"promptLifetimeSec": 120,
"rule": "ab BRIDGE_SDK 2.1.30: a verb parked on a HUMAN never bare-timeouts; it answers this shape",
"stillRunning": "true = the wait continues in the background: re-call the SAME verb with the SAME args to re-attach (no second prompt) or watch pup_readiness.active[]; false = the human must act first, then re-issue the verb"
},
"slowVerbs": [
"pup_open_window",
"pup_prewarm",
"pup_use"
],
"statusVerb": "pup_readiness",
"timings": {
"open_window_warm": {
"confidence": "measured",
"estimatedSec": 11,
"samples": 20
}
}
},
"related": [
"pup_status"
],
"status": "ok",
"statusVerb": "pup_readiness",
"success": true,
"timeoutSeconds": 60,
"verbs": [
{
"example": {},
"hint": "START HERE for window management: everything YOUR thread owns — windows, tabs, urls, titles, state — with ready-to-run next steps. Zero args. You NEVER need an hwnd, desktop_find_window, or desktop_screenshot_window for a pup window: pup keys every window to its owning --ai-thread name and resolves ids for you — omit sessionId in any pup verb to target your own window, or pass \"ai-thread\" to address a thread by name (the CLI's --ai-thread flag, same spelling). pup_screenshot {} screenshots it; pup_reload {} refreshes it.",
"input": {
"ai-thread": "optional str — inspect another thread's windows (read-only listing); default = the calling thread. The CLI flag's exact spelling; aiThread also accepted"
},
"longRunning": false,
"name": "pup_my_windows",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "START HERE for window management: everything YOUR thread owns — windows, tabs, urls, titles, state — with ready-to-run next steps. Zero args. You NEVER need an hwnd, desktop_find_window, or desktop_screenshot_window for a pup window: pup keys every window to its owning --ai-thread name and resolves ids for you — omit sessionId in any pup verb to target your own window, or pass \"ai-thread\" to address a thread by name (the CLI's --ai-thread flag, same spelling). pup_screenshot {} screenshots it; pup_reload {} refreshes it.",
"timeoutSeconds": 10
},
{
"example": {
"height": 540,
"owner": "mytask",
"sessionId": "mytask-web",
"url": "https://example.com",
"width": 960
},
"hint": "Opens a generic, fully-controllable pup window (a fresh isolated Chrome/Edge process — never your real signed-in browser) that you then drive by sessionId. To drive the user's REAL Chrome/Edge, use the Adom browser extension's nbrowser_* verbs instead.",
"input": {
"appIconB64": "optional base64 PNG — override the app icon worn in the taskbar overlay. Usually UNNECESSARY: pup auto-fetches the page's own <link rel=\"icon\"> favicon (the adom-ui-design standard artifact every app must serve) and wears it automatically. An app-looking URL with NO favicon gets a reprimand hint.",
"appName": "optional str — the APP this window is driving (e.g. \"shotlog\"); shown in the hover tooltip",
"autoFlash": "optional bool (default true) — mutating verbs auto-flash this window's taskbar (debounced, never steals focus) so the user notices the agent touched it; pass false to make this window silent by default",
"foreground": "optional bool — request showing the window on the user's screen. GATED (v1.8.70): requires foregroundReason too, else the open succeeds but stays BACKGROUND with foregroundDenied set. Only when the USER explicitly asked to watch.",
"foregroundReason": "required WITH foreground:true — quote/paraphrase what the user said that justifies putting a window on their screen (min 10 chars; logged + recorded in lastAgentUpdate, auditable)",
"height": "optional int px",
"isolated": "optional bool — private throwaway profile: fresh-login tests, acting as a different user. REASON-GATED (v2.0.101): requires isolationReason or the open is refused — every window defaults to the shared adom-you profile",
"isolationReason": "required WITH isolated:true — why this window must NOT ride the shared adom-you profile (min 10 chars; logged, auditable). webSecurity:false and wikiView:public carry their own built-in reason",
"owner": "optional str — your thread/task label; lets pup protect this window from other threads",
"profile": "optional str — a named durable jar; DEFAULT is the shared \"adom-you\" profile (signed-in state shared across windows). isolated:true overrides to a throwaway",
"sessionId": "optional str — OMIT IT (recommended): your thread gets its OWN window keyed on your --ai-thread name; the first open creates it, later opens become TABS in it, and no other thread can touch it. Pass an explicit id only when you need a SEPARATE window (task-prefix it, e.g. \"mytask-web\")",
"silent": "optional bool — suppress the auto-flash for just this call",
"takeover": "optional bool — claim a window owned by another thread (only when the user explicitly asks)",
"updateNote": "optional str — a short \"what I did\" note, surfaced back in list_tabs/list_windows as lastAgentUpdate so the user knows what changed",
"url": "optional str",
"webSecurity": "optional false — dev escape hatch for cross-origin eval; FORCES isolation so insecure flags never touch the credentialed profile",
"width": "optional int px — sizes for screenshot framing, stays background",
"wikiView": "optional \"authed\"|\"public\" — for wiki.adom.inc URLs. THREE distinct cases: (1) OMIT = the shared adom-you profile, LOGGED IN as the user if they have signed into the wiki (the usual case); this is NOT anonymous. (2) \"public\" = the SERVER renders the page exactly as a signed-out visitor sees it via the ?view=public param (adom/wiki#126: request user nulled, byte-identical to logged-out, private pages 404) — the window STAYS on the shared profile, session untouched, no isolated jar; use this to verify a publish did not leak private source. (3) \"authed\" = the explicit logged-in view (30-day SSO; first use may need a one-time login — response says wikiLoginNeeded). To compare \"what I see\" vs \"what the world sees\", open one \"authed\" (or omit) AND one \"public\" tab — do NOT rely on omit for the public view.",
"x": "optional int px",
"y": "optional int px"
},
"longRunning": false,
"name": "pup_open_window",
"output": {
"success": "bool"
},
"pitfalls": [
"sessionId is OPTIONAL: omit it and your thread gets its OWN window (keyed on your --ai-thread name; later opens become tabs in it). Pass one only for a deliberate separate window — it is then your handle for every later call",
"profile defaults to the durable shared 'adom-you' profile (logins/localStorage persist + are shared across all pup windows); isolated:true for a private throwaway — omit it for a plain \"open in pup\"",
"sessionIds are SHARED across all AI threads on this desktop — a generic id (\"wiki\", \"test\") may collide with another thread's window and navigating it away steals their work. Use a task-prefixed sessionId + pass owner:\"<your-task>\" so pup can protect it",
"reusing an existing sessionId with a new url NAVIGATES that window — check pup_status (shows owner per window) first if unsure"
],
"related": [
"pup_navigate",
"pup_list_windows",
"pup_close_window"
],
"statusVerb": null,
"summary": "Open a generic pup window — a fresh isolated Chrome/Edge process (never your real signed-in browser), fully drivable via CDP. ALWAYS opens in the BACKGROUND (does not steal focus; never disturbs the user's main work; still fully screenshottable/drivable) UNLESS you pass foreground:true — do that ONLY when the user explicitly wants to watch. Pass width+height (+ optional x,y, screen px) to place it at a specific size/position for screenshot framing — this NO LONGER foregrounds it (sizing stays in the background too; default unsized is maximized). profile defaults to the durable shared 'adom-you' profile (logins/localStorage persist + are shared across all pup windows); isolated:true for a private throwaway. OWNERSHIP: sessionIds are shared across ALL AI threads — use a task-prefixed sessionId + owner:\"<your-task>\" so pup can refuse other threads stealing your window (reusing an existing id with a new url navigates it away; declared cross-owner reuse errors with session_owned_by_another_thread unless takeover:true). (For the user's REAL Chrome/Edge, use the Adom extension's nbrowser_* verbs.)",
"timeoutSeconds": 60
},
{
"example": {
"sessionId": "work",
"url": "https://example.com"
},
"hint": "Adds a tab to an existing session; returns the new tabId.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"silent": "optional bool — suppress the auto-flash for this call",
"updateNote": "optional str — short \"what I did\" note surfaced in list_tabs as lastAgentUpdate",
"url": "optional str"
},
"longRunning": false,
"name": "pup_open_tab",
"output": {
"success": "bool"
},
"pitfalls": [
"the session must already exist (pup_open_window first)"
],
"related": [
"pup_switch_tab",
"pup_list_tabs",
"pup_close_tab"
],
"statusVerb": null,
"summary": "Open a new tab in an EXISTING session/window (returns {tabId, tabCount, activeTabId} — no need to diff list_tabs). This is the right verb for multi-URL work: ONE window with many tabs (one taskbar button), not many windows. The window stays in the background; the tab auto-flashes the taskbar (debounced) so the user notices. The USER can click the window's taskbar button at any time to view it — pup never pulls it back down.",
"timeoutSeconds": 30
},
{
"example": {
"sessionId": "work"
},
"hint": "Closes one tab; the session stays open.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"tabId": "optional str (default active)"
},
"longRunning": false,
"name": "pup_close_tab",
"output": {
"success": "bool"
},
"pitfalls": [
"omit tabId to close the active tab — closing the last tab may close the window"
],
"related": [
"pup_close_window",
"pup_list_tabs"
],
"statusVerb": null,
"summary": "Close a tab.",
"timeoutSeconds": 15
},
{
"example": {
"sessionId": "work"
},
"hint": "Closes the whole session and all its tabs. Destructive.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_close_window",
"output": {
"success": "bool"
},
"pitfalls": [
"this ends the session — its sessionId is no longer valid afterward"
],
"related": [
"pup_list_windows"
],
"statusVerb": null,
"summary": "Close a window/session (its tabs go too).",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "Everything about ONE pup window as JSON — owner AI thread, container, profile, tabs, age, last agent action, and the window's hwnd (for desktop_screenshot_window when you need the browser chrome in frame). For an AI caller this is a PURE DATA query: nothing is drawn on the user's screen. Visual surfaces are user-initiated only — a jump-list click shows the native taskbar caption, a toolbar-popup click shows the in-page floaty card. showCaption:true opts an AI caller into the caption ONLY when the user asked to have the window identified on screen. Read-only, never owner-gated.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"showCaption": "optional bool — draw the ~12s taskbar caption too; ONLY when the user asked to see which window this is"
},
"longRunning": false,
"name": "pup_window_info",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Everything about ONE pup window as JSON — owner AI thread, container, profile, tabs, age, last agent action, and the window's hwnd (for desktop_screenshot_window when you need the browser chrome in frame). For an AI caller this is a PURE DATA query: nothing is drawn on the user's screen. Visual surfaces are user-initiated only — a jump-list click shows the native taskbar caption, a toolbar-popup click shows the in-page floaty card. showCaption:true opts an AI caller into the caption ONLY when the user asked to have the window identified on screen. Read-only, never owner-gated.",
"timeoutSeconds": 15
},
{
"example": {
"sessionId": "wiki-bmv080",
"view": "authed"
},
"hint": "Flip a WIKI pup window between the logged-in and public view IN PLACE: every wiki tab reloads with the server-side ?view=public param appended (public) or stripped (authed) — adom/wiki#126 renders the request exactly as a signed-out visitor while the session stays untouched, so there is no relaunch, no cookie wipe, no profile switch (the legacy jar relaunch survives only as a fallback for servers that ignore the param). This is the callback for the per-window taskbar jump-list task (WINDOWS ONLY) — a USER-initiated action. AI threads should NOT call this; pass wikiView:\"authed\"|\"public\" on pup_open_window instead.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"view": "required \"authed\"|\"public\"|\"toggle\" — toggle flips whatever the window currently shows (the Alt+Shift+V hotkey form)"
},
"longRunning": false,
"name": "pup_wiki_set_view",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Flip a WIKI pup window between the logged-in and public view IN PLACE: every wiki tab reloads with the server-side ?view=public param appended (public) or stripped (authed) — adom/wiki#126 renders the request exactly as a signed-out visitor while the session stays untouched, so there is no relaunch, no cookie wipe, no profile switch (the legacy jar relaunch survives only as a fallback for servers that ignore the param). This is the callback for the per-window taskbar jump-list task (WINDOWS ONLY) — a USER-initiated action. AI threads should NOT call this; pass wikiView:\"authed\"|\"public\" on pup_open_window instead.",
"timeoutSeconds": 45
},
{
"example": {
"sessionId": "work",
"url": "https://example.com"
},
"hint": "Drives the active tab to url and waits for load. Verify with a screenshot before asserting success.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"url": "required str"
},
"longRunning": false,
"name": "pup_navigate",
"output": {
"success": "bool"
},
"pitfalls": [
"navigation can race SPA routing — confirm with pup_screenshot",
"some sites need pup_wait for a selector after navigate"
],
"related": [
"pup_screenshot",
"pup_wait",
"pup_reload"
],
"statusVerb": null,
"summary": "Navigate the active tab to a URL.",
"timeoutSeconds": 45
},
{
"example": {
"sessionId": "work"
},
"hint": "History back on the active tab.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_back",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [
"pup_forward",
"pup_navigate"
],
"statusVerb": null,
"summary": "History back.",
"timeoutSeconds": 20
},
{
"example": {
"sessionId": "work"
},
"hint": "History forward on the active tab.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_forward",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [
"pup_back",
"pup_navigate"
],
"statusVerb": null,
"summary": "History forward.",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "Paint the Windows taskbar PROGRESS BAR on your window during a LONG multi-stage task (crawling a site, login->search->download loops, batch harvesting datasheets/STEP files) so the user sees work happening at a glance. mode:\"indeterminate\" (pulsing) to start, mode:\"value\" with value:0-100 as stages complete, mode:\"off\" when done or aborted (always clear!). Optional note:\"12/40 datasheets\" shows on the button hover tooltip. YOUR judgment: a single quick page open does NOT warrant a progress bar. See the pup-progress skill.",
"input": {
"mode": "\"indeterminate\" | \"value\" | \"off\"",
"note": "optional short stage label for the hover tooltip",
"sessionId": "optional — defaults to your thread's own window",
"value": "optional 0-100 (mode:\"value\")"
},
"longRunning": false,
"name": "pup_progress",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Paint the Windows taskbar PROGRESS BAR on your window during a LONG multi-stage task (crawling a site, login->search->download loops, batch harvesting datasheets/STEP files) so the user sees work happening at a glance. mode:\"indeterminate\" (pulsing) to start, mode:\"value\" with value:0-100 as stages complete, mode:\"off\" when done or aborted (always clear!). Optional note:\"12/40 datasheets\" shows on the button hover tooltip. YOUR judgment: a single quick page open does NOT warrant a progress bar. See the pup-progress skill.",
"timeoutSeconds": 8
},
{
"example": {
"sessionId": "work"
},
"hint": "Reloads the active tab.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_reload",
"output": {
"success": "bool"
},
"pitfalls": [
"A page with unsaved changes raises a native \"Reload site?\" dialog that BLOCKS the window: the reload appears to time out and so does everything else. Answer it with pup_dialog."
],
"related": [
"pup_navigate",
"pup_wait",
"pup_dialog"
],
"statusVerb": null,
"summary": "Reload the active tab.",
"timeoutSeconds": 30
},
{
"example": {
"selector": "button#go",
"sessionId": "work"
},
"hint": "Clicks by CSS selector (preferred) or by x,y coords. Selector is more robust across layouts.",
"input": {
"button": "optional \"left\"|\"right\"|\"middle\"",
"clickCount": "optional int 1-3",
"domClick": "optional bool — dispatch a synthetic element.click() instead of a trusted CDP click; for React controls that ignore trusted clicks",
"selector": "optional str",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"x": "optional int",
"y": "optional int"
},
"longRunning": false,
"name": "pup_click",
"output": {
"success": "bool"
},
"pitfalls": [
"selector must match exactly one visible element — verify with pup_evaluate first",
"coords are viewport-relative; a scrolled element may be off-screen"
],
"related": [
"pup_type",
"pup_input_dispatch",
"pup_screenshot"
],
"statusVerb": null,
"summary": "Click an element (by selector or coords). Selector clicks LOCATE the element once then click by its center coordinates (fast on huge/animated DOMs, where page.click used to hit the 15s wall). Response includes method. If a React toggle/like/heart does NOT change state after a normal click, that control ignores trusted clicks — retry with domClick:true to fire a synthetic element.click().",
"timeoutSeconds": 20
},
{
"example": {
"label": "your Google account",
"reason": "clicking your Google account to finish signing into Autodesk",
"sessionId": "adsk",
"x": 900,
"y": 379
},
"hint": "RESPECTFUL real-cursor click for a surface pup CDP cannot drive (a NATIVE OS dialog, or a cross-origin FedCM \"Sign in with Google\" account chooser that rejects every in-page click). Do NOT hand-roll raise+desktop_click for these — use THIS. It: captions the reason + toasts BEFORE touching the screen; foregrounds; then WAITS, detecting if the user alt-tabbed away and holding (captioning \"Adom is waiting — click back when ready\") until the user is actually on the window; then runs the TIGHT real-cursor hover->click that FedCM accepts (interleaving any screenshot/eval between raise and click makes the click silently no-op); captions each step. Times out as user_not_ready clicking NOTHING if they never return. First take a desktop_screenshot_window of the session to read the target's WINDOW-pixel x,y.",
"input": {
"label": "required str — WHAT you are clicking (e.g. \"your Google account\")",
"maxWaitMs": "optional int — how long to wait for the user (default 120000)",
"reason": "required str — WHY you must click (shown to the user as a caption)",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"x": "required int — WINDOW-image pixel of the target (from desktop_screenshot_window)",
"y": "required int"
},
"longRunning": false,
"name": "pup_assisted_click",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "RESPECTFUL real-cursor click for a surface pup CDP cannot drive (a NATIVE OS dialog, or a cross-origin FedCM \"Sign in with Google\" account chooser that rejects every in-page click). Do NOT hand-roll raise+desktop_click for these — use THIS. It: captions the reason + toasts BEFORE touching the screen; foregrounds; then WAITS, detecting if the user alt-tabbed away and holding (captioning \"Adom is waiting — click back when ready\") until the user is actually on the window; then runs the TIGHT real-cursor hover->click that FedCM accepts (interleaving any screenshot/eval between raise and click makes the click silently no-op); captions each step. Times out as user_not_ready clicking NOTHING if they never return. First take a desktop_screenshot_window of the session to read the target's WINDOW-pixel x,y.",
"timeoutSeconds": 130
},
{
"example": {
"clear": true,
"selector": "#user",
"sessionId": "work",
"text": "adominc1"
},
"hint": "Types into the focused or selector-targeted field.",
"input": {
"clear": "optional bool — empty the field first (replace, not append)",
"selector": "optional str",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"text": "required str"
},
"longRunning": false,
"name": "pup_type",
"output": {
"success": "bool"
},
"pitfalls": [
"focus the field first (pup_click the input) or pass selector",
"does not clear existing text — select-all + delete if you need a clean field"
],
"related": [
"pup_click",
"pup_press_key"
],
"statusVerb": null,
"summary": "Type text into a field via real CDP keystrokes (isTrusted). Reads the value back and returns valueLanded — real keystrokes only register in a FOREGROUNDED window, so if valueLanded:false the field stayed empty (the silent no-op): use pup_fill (background-safe) for a non-React input, or pup_login {realKeystrokes:true} for a login form. Pass clear:true to REPLACE instead of appending.",
"timeoutSeconds": 20
},
{
"example": {
"selector": "#email",
"sessionId": "work",
"text": "[email protected]"
},
"hint": "Set a field's value in the BACKGROUND (no foreground, no keystrokes): writes .value via the native setter and fires input+change so React/Vue/Angular controlled inputs pick it up. The fix for pup_type's silent no-op on a backgrounded window. Reads the value back and returns valueLanded. For React-MASKED password fields that reject programmatic writes, use pup_login {realKeystrokes:true} instead.",
"input": {
"selector": "required str",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"text": "required str"
},
"longRunning": false,
"name": "pup_fill",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Set a field's value in the BACKGROUND (no foreground, no keystrokes): writes .value via the native setter and fires input+change so React/Vue/Angular controlled inputs pick it up. The fix for pup_type's silent no-op on a backgrounded window. Reads the value back and returns valueLanded. For React-MASKED password fields that reject programmatic writes, use pup_login {realKeystrokes:true} instead.",
"timeoutSeconds": 20
},
{
"example": {
"key": "a",
"modifiers": [
"Control"
],
"sessionId": "work"
},
"hint": "Presses a key or chord (Enter, Ctrl+A, Tab).",
"input": {
"key": "required str",
"modifiers": "optional array — any of [\"Control\",\"Shift\",\"Alt\",\"Meta\"] (aliases ctrl/cmd/command/option accepted); held down around the key press",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_press_key",
"output": {
"success": "bool"
},
"pitfalls": [
"chord syntax is \"Ctrl+A\" — verify the page has focus on the intended element"
],
"related": [
"pup_type",
"pup_input_dispatch"
],
"statusVerb": null,
"summary": "Press a key, optionally with modifier chords held (Ctrl+A, Ctrl+V, Shift+Tab).",
"timeoutSeconds": 15
},
{
"example": {},
"hint": "⛔ READ BEFORE USING AD's desktop_click / desktop_type / desktop_press_key ON A PUP WINDOW. Native OS input does NOT target a window — it goes to WHATEVER WINDOW HAS OS FOCUS at that instant. This user runs many AI threads and alt-tabs away from a foregrounded window almost immediately. If you fire native input without warning them, your keystrokes land in THEIR document (this happened: a username was typed into the user's own window). REQUIRED: notify_user toast + desktop_caption FIRST, tell them explicitly \"don't type or click until I say done\", wait until the window is genuinely foreground, re-verify immediately before EACH event, and caption when done. pup_assisted_click already does all of this — use it. And ALWAYS prefer CDP input (pup_click/pup_type/pup_hover): it needs no foreground and disturbs nobody. A native verb returning ok:true means the event was dispatched to the OS, NOT that it reached your window.",
"input": {},
"longRunning": false,
"name": "pup_NATIVE_INPUT_WARNING",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "⛔ READ BEFORE USING AD's desktop_click / desktop_type / desktop_press_key ON A PUP WINDOW. Native OS input does NOT target a window — it goes to WHATEVER WINDOW HAS OS FOCUS at that instant. This user runs many AI threads and alt-tabs away from a foregrounded window almost immediately. If you fire native input without warning them, your keystrokes land in THEIR document (this happened: a username was typed into the user's own window). REQUIRED: notify_user toast + desktop_caption FIRST, tell them explicitly \"don't type or click until I say done\", wait until the window is genuinely foreground, re-verify immediately before EACH event, and caption when done. pup_assisted_click already does all of this — use it. And ALWAYS prefer CDP input (pup_click/pup_type/pup_hover): it needs no foreground and disturbs nobody. A native verb returning ok:true means the event was dispatched to the OS, NOT that it reached your window.",
"timeoutSeconds": 0
},
{
"example": {
"reset": true,
"sessionId": "work"
},
"hint": "Pin the page viewport (CDP device-metrics) to an exact size for deterministic screenshots — OR clear that pin. ⚠ A pin PERSISTS: it survives navigation and hard reload, and while set the window stops tracking OS resizing (a human resizing it sees no reflow, which looks exactly like an app layout bug). ALWAYS clear it when done. Reported as emulatedViewport in pup_status / pup_list_windows.",
"input": {
"deviceScaleFactor": "optional number (default 1)",
"height": "int — required unless reset",
"reset": "optional bool — CLEAR the override and track the OS window again (width/height not needed)",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"width": "int — required unless reset"
},
"longRunning": false,
"name": "pup_set_viewport",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Pin the page viewport (CDP device-metrics) to an exact size for deterministic screenshots — OR clear that pin. ⚠ A pin PERSISTS: it survives navigation and hard reload, and while set the window stops tracking OS resizing (a human resizing it sees no reflow, which looks exactly like an app layout bug). ALWAYS clear it when done. Reported as emulatedViewport in pup_status / pup_list_windows.",
"timeoutSeconds": 15
},
{
"example": {},
"hint": "Status/trigger for the toolbar extension, which AUTO-INSTALLS invisibly at every profile launch (transient pipe-launch + CDP Extensions.loadUnpacked; persists in the profile). Running profiles pick it up on their next launch; cold profiles install immediately.",
"input": {
"profile": "optional, default adom-you"
},
"longRunning": false,
"name": "pup_install_toolbar",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Status/trigger for the toolbar extension, which AUTO-INSTALLS invisibly at every profile launch (transient pipe-launch + CDP Extensions.loadUnpacked; persists in the profile). Running profiles pick it up on their next launch; cold profiles install immediately.",
"timeoutSeconds": 30
},
{
"example": {},
"hint": "TEST SEAM: simulate a user click on the floaty pencil (fires the same host click handler a mouse does; the sweep then starts annotate within ~4s). Built for the recurring floaty ralph — assert the annotate overlay appears after calling this.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"tabId": "optional tab"
},
"longRunning": false,
"name": "pup_floaty_click",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "TEST SEAM: simulate a user click on the floaty pencil (fires the same host click handler a mouse does; the sweep then starts annotate within ~4s). Built for the recurring floaty ralph — assert the annotate overlay appears after calling this.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "Start the HUMAN annotation overlay on a window's active tab (pen/arrow/box/text toolbar injected in-page; also on every window's taskbar jump list as \"Annotate this page\"). Two capture modes the user can also flip in the toolbar: \"auto\" (default) captures the instant the mouse lifts — the one-red-circle case; \"multi\" accumulates shapes (color swatches: red/blue/yellow one click, more in a flyout) and captures ONCE on Done. Done captures a PNG AND leaves the drawing in the DOM, so the owning thread's next pup_screenshot shows exactly what the user marked — check session.lastAnnotation via pup_list_windows. action:\"cancel\" removes the overlay.",
"input": {
"action": "optional \"cancel\"",
"mode": "optional \"auto\"|\"multi\"",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_annotate",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Start the HUMAN annotation overlay on a window's active tab (pen/arrow/box/text toolbar injected in-page; also on every window's taskbar jump list as \"Annotate this page\"). Two capture modes the user can also flip in the toolbar: \"auto\" (default) captures the instant the mouse lifts — the one-red-circle case; \"multi\" accumulates shapes (color swatches: red/blue/yellow one click, more in a flyout) and captures ONCE on Done. Done captures a PNG AND leaves the drawing in the DOM, so the owning thread's next pup_screenshot shows exactly what the user marked — check session.lastAnnotation via pup_list_windows. action:\"cancel\" removes the overlay.",
"timeoutSeconds": 15
},
{
"example": {},
"hint": "Open the LIVE pup management dashboard in its OWN window (its own profile, so its own taskbar icon). Shows every window pup is driving as taskbar button -> window(s) -> tabs with each tab favicon, owning AI thread, foreground/background + the reason given to foreground it, highFps lease, uptime, and WHY each overlay icon was chosen. Live over SSE. Reuses the one window on repeat calls; backgrounded by default like any pup window.",
"input": {},
"longRunning": false,
"name": "pup_dashboard",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Open the LIVE pup management dashboard in its OWN window (its own profile, so its own taskbar icon). Shows every window pup is driving as taskbar button -> window(s) -> tabs with each tab favicon, owning AI thread, foreground/background + the reason given to foreground it, highFps lease, uptime, and WHY each overlay icon was chosen. Live over SSE. Reuses the one window on repeat calls; backgrounded by default like any pup window.",
"timeoutSeconds": 30
},
{
"example": {},
"hint": "Report pup dependency health (wiki issue #15): depsPresent, selfInstalledThisBoot, lastError. Use this to answer \"is pup broken?\" without reading spawn logs.",
"input": {},
"longRunning": false,
"name": "pup_deps",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Report pup dependency health (wiki issue #15): depsPresent, selfInstalledThisBoot, lastError. Use this to answer \"is pup broken?\" without reading spawn logs.",
"timeoutSeconds": 10
},
{
"example": {
"selector": "#menu",
"sessionId": "work"
},
"hint": "Move the pointer over a target WITHOUT clicking (reveals tooltips / hover menus). Glides the visible Adom cursor there too.",
"input": {
"intent": "optional str — narrated on the cursor label",
"selector": "optional str",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"steps": "optional int (default 8)",
"x": "optional int",
"y": "optional int"
},
"longRunning": false,
"name": "pup_hover",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Move the pointer over a target WITHOUT clicking (reveals tooltips / hover menus). Glides the visible Adom cursor there too.",
"timeoutSeconds": 15
},
{
"example": {
"sessionId": "work"
},
"hint": "Maximize (or restore/fullscreen/minimize) a pup window via CDP — no AD desktop verb required. Does NOT foreground it.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"state": "optional \"maximized\"|\"normal\"|\"minimized\"|\"fullscreen\" (default maximized)"
},
"longRunning": false,
"name": "pup_maximize",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Maximize (or restore/fullscreen/minimize) a pup window via CDP — no AD desktop verb required. Does NOT foreground it.",
"timeoutSeconds": 15
},
{
"example": {
"avatarB64": "<base64 png>",
"name": "John Lauer"
},
"hint": "Set the Adom identity shown in the floating owner chip on every pup window (avatar + name). Chrome's own profile chip cannot take a custom local image (Google sign-in only), so the user's Adom avatar lives here instead. Pass a pre-circle-cropped PNG as base64. Applies to live windows immediately + persists.",
"input": {
"avatarB64": "optional str — base64 PNG (ideally ~48px, circle-cropped); the leading data: prefix is stripped if present",
"clear": "optional bool — remove the stored avatar + name",
"enabled": "optional bool — turn the whole owner chip on/off",
"name": "optional str — display name shown in the chip tooltip"
},
"longRunning": false,
"name": "pup_set_identity",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Set the Adom identity shown in the floating owner chip on every pup window (avatar + name). Chrome's own profile chip cannot take a custom local image (Google sign-in only), so the user's Adom avatar lives here instead. Pass a pre-circle-cropped PNG as base64. Applies to live windows immediately + persists.",
"timeoutSeconds": 15
},
{
"example": {
"sessionId": "work"
},
"hint": "PNG of the page. Your primary way to SEE state — call it after navigate/click to confirm.",
"input": {
"fullPage": "optional bool",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_screenshot",
"output": {
"success": "bool"
},
"pitfalls": [
"default is the viewport; pass fullPage:true for the whole scroll height"
],
"related": [
"pup_screenshot_full_res",
"pup_navigate"
],
"statusVerb": null,
"summary": "Screenshot the page (PNG; fullPage optional). NOTE: fullPage only covers DOCUMENT-level scroll — on SPAs that scroll inside a nested container it returns just the viewport + a nestedScroll hint; use pup_screenshot_element or pup_scroll for those.",
"timeoutSeconds": 30
},
{
"example": {
"selector": ".download-card",
"sessionId": "work"
},
"hint": "Screenshot ONE element, resolved by CSS selector OR visible text (pierces shadow DOM), scrolled into view first. The clean way to grab a single card/widget on a component-heavy page. Text matches the TIGHTEST text node — to capture the enclosing CARD, add closest (e.g. {text:\"Download…\", closest:\".download-card\"}); with closest, an ambiguous phrase still lands on the real widget (skips prose that has no such ancestor). Returns base64 + filePath like pup_screenshot.",
"input": {
"closest": "optional selector — climb to the nearest ancestor matching it (the card container)",
"deep": "optional bool — pierce shadow DOM (default true)",
"padding": "optional int px around the element",
"selector": "CSS selector (or use text)",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"text": "visible text to match (or use selector)"
},
"longRunning": false,
"name": "pup_screenshot_element",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Screenshot ONE element, resolved by CSS selector OR visible text (pierces shadow DOM), scrolled into view first. The clean way to grab a single card/widget on a component-heavy page. Text matches the TIGHTEST text node — to capture the enclosing CARD, add closest (e.g. {text:\"Download…\", closest:\".download-card\"}); with closest, an ambiguous phrase still lands on the real widget (skips prose that has no such ancestor). Returns base64 + filePath like pup_screenshot.",
"timeoutSeconds": 30
},
{
"example": {
"sessionId": "work",
"toText": "Download"
},
"hint": "Scroll the ACTUAL scrolling element (nearest ancestor whose scrollHeight>clientHeight, NOT just window — window.scrollTo no-ops on nested-scroll SPAs). Scroll by delta {dy,dx} OR to an element {toSelector|toText} (pierces shadow DOM). Returns {scrollElement, scrollTop, scrollHeight, clientHeight} so you can confirm it landed.",
"input": {
"behavior": "optional auto|smooth",
"block": "optional start|center|end (for scroll-to; default center)",
"dx": "optional int px",
"dy": "optional int px (down+/up-)",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"toSelector": "optional CSS selector to scroll to",
"toText": "optional visible text to scroll to"
},
"longRunning": false,
"name": "pup_scroll",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Scroll the ACTUAL scrolling element (nearest ancestor whose scrollHeight>clientHeight, NOT just window — window.scrollTo no-ops on nested-scroll SPAs). Scroll by delta {dy,dx} OR to an element {toSelector|toText} (pierces shadow DOM). Returns {scrollElement, scrollTop, scrollHeight, clientHeight} so you can confirm it landed.",
"timeoutSeconds": 30
},
{
"example": {
"height": 900,
"sessionId": "work",
"width": 1280
},
"hint": "Set the page viewport (CDP device-metrics) deterministically, independent of the OS window size — fixes a too-small innerWidth so fullPage/element shots render at a known width. width+height required.",
"input": {
"deviceScaleFactor": "optional number (default 1)",
"height": "required int px",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"width": "required int px"
},
"longRunning": false,
"name": "pup_set_viewport",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Set the page viewport (CDP device-metrics) deterministically, independent of the OS window size — fixes a too-small innerWidth so fullPage/element shots render at a known width. width+height required.",
"timeoutSeconds": 15
},
{
"example": {
"expression": "document.title",
"sessionId": "work"
},
"hint": "Runs JS in the page and returns the result — use it to read DOM state or verify selectors before acting.",
"input": {
"expression": "required str — aliases accepted: expr, script, js, code",
"frame": "optional str — run inside this iframe instead of the top document",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_evaluate",
"output": {
"success": "bool"
},
"pitfalls": [
"the expression must be serializable JSON in its return value",
"runs in the page context, not Node"
],
"related": [
"pup_click",
"pup_fetch_url"
],
"statusVerb": null,
"summary": "Evaluate JS in the page and return the result — THE verb for reading DOM state / asserting on a page (same handler as pup_eval). Add frame:\"<name|url-substring|index>\" to run inside an iframe.",
"timeoutSeconds": 30
},
{
"example": {
"sessionId": "work",
"url": "https://api.example.com"
},
"hint": "Fetches a URL using the tab's live cookies/session — for authed APIs the bare CLI can't reach. Returns bodyBase64.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"url": "required str"
},
"longRunning": false,
"name": "pup_fetch_url",
"output": {
"success": "bool"
},
"pitfalls": [
"for session-scoped URLs pass the tabId whose cookies you need",
"returns base64 — decode it caller-side"
],
"related": [
"pup_navigate",
"pup_evaluate"
],
"statusVerb": null,
"summary": "Fetch a URL's content via the browser (cookies/session intact).",
"timeoutSeconds": 45
},
{
"example": {
"selector": "button.download",
"sessionId": "work"
},
"hint": "Download a file THROUGH THE BROWSER, exactly as the user clicking it would — real session, real cookies, real anti-bot cookies — and Chrome saves it to the Downloads folder. This is the right verb for vendor files (datasheets, KiCad/Altium libraries, STEP 3D models) that a server-side fetch/curl can never get past the site's bot wall. Pass selector to click the actual download button (authentic), or url to force-download via an in-page a[download]. Confirms completion via Chrome's download events and returns the ACTUAL saved path + byte count + file magic. For a gated file, log in on the window first (pup_login).",
"input": {
"saveAs": "optional str — filename override",
"saveDir": "optional str — default the user's Downloads folder",
"selector": "optional str — the real download control to click",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"url": "optional str — download this URL via an in-page a[download] click"
},
"longRunning": false,
"name": "pup_download",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Download a file THROUGH THE BROWSER, exactly as the user clicking it would — real session, real cookies, real anti-bot cookies — and Chrome saves it to the Downloads folder. This is the right verb for vendor files (datasheets, KiCad/Altium libraries, STEP 3D models) that a server-side fetch/curl can never get past the site's bot wall. Pass selector to click the actual download button (authentic), or url to force-download via an in-page a[download]. Confirms completion via Chrome's download events and returns the ACTUAL saved path + byte count + file magic. For a gated file, log in on the window first (pup_login).",
"timeoutSeconds": 100
},
{
"example": {
"sessionId": "work",
"type": "mousePressed",
"x": 100,
"y": 200
},
"hint": "Low-level CDP mouse/keyboard input at coords — beats some overlays/iframes that swallow synthetic clicks.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"type": "required str",
"x": "optional int",
"y": "optional int"
},
"longRunning": false,
"name": "pup_input_dispatch",
"output": {
"success": "bool"
},
"pitfalls": [
"coords are viewport pixels",
"last-resort when pup_click can't reach the element — still cannot pass Cloudflare interactive challenges"
],
"related": [
"pup_click",
"pup_press_key"
],
"statusVerb": null,
"summary": "Low-level input (mouse/keyboard) at coords — beats some overlays.",
"timeoutSeconds": 20
},
{
"example": {
"sessionId": "work"
},
"hint": "Starts video recording of the page for this session.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_record_start",
"output": {
"success": "bool"
},
"pitfalls": [
"one recording per session — stop the current one before starting another"
],
"related": [
"pup_record_stop",
"pup_record_status"
],
"statusVerb": null,
"summary": "Start recording the page (video).",
"timeoutSeconds": 20
},
{
"example": {
"sessionId": "work"
},
"hint": "Stops recording and returns the saved file path.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_record_stop",
"output": {
"success": "bool"
},
"pitfalls": [
"no-op if nothing is recording for this session"
],
"related": [
"pup_record_start",
"pup_record_list"
],
"statusVerb": null,
"summary": "Stop recording; returns the saved file.",
"timeoutSeconds": 30
},
{
"example": {
"sessionId": "work"
},
"hint": "Whether a recording is active for the session.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_record_status",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [
"pup_record_start",
"pup_record_stop"
],
"statusVerb": null,
"summary": "Recording status for a session.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "Lists saved page recordings.",
"input": {},
"longRunning": false,
"name": "pup_record_list",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [
"pup_record_start"
],
"statusVerb": null,
"summary": "List recordings.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "Open pup's Chrome screen-share recorder HUD (WebM; consent = the visible HUD). Canonical name (pup-bridge#94).",
"input": {
"reason": "str (required)"
},
"longRunning": false,
"name": "pup_recorder_open",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Open pup's Chrome screen-share recorder HUD (WebM; consent = the visible HUD). Canonical name (pup-bridge#94).",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "Start a whole-screen recording through Chrome screen-share (WebM VP9, system audio + mic). Canonical name; for a background no-browser MP4 of one window use ab-core desktop_record_window_start.",
"input": {
"audio": "bool",
"confirmDesktopNotTabRecording": "true",
"fps": "int",
"maxDurationMs": "int",
"reason": "str (required)"
},
"longRunning": false,
"name": "pup_screen_record_start",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Start a whole-screen recording through Chrome screen-share (WebM VP9, system audio + mic). Canonical name; for a background no-browser MP4 of one window use ab-core desktop_record_window_start.",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "Stop the Chrome screen recording; returns the .webm path.",
"input": {},
"longRunning": false,
"name": "pup_screen_record_stop",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Stop the Chrome screen recording; returns the .webm path.",
"timeoutSeconds": 30
},
{
"example": {},
"hint": "Status of the Chrome screen recorder + any active clip.",
"input": {},
"longRunning": false,
"name": "pup_screen_record_status",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Status of the Chrome screen recorder + any active clip.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "List completed Chrome screen recordings on disk.",
"input": {},
"longRunning": false,
"name": "pup_screen_record_list",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "List completed Chrome screen recordings on disk.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "Close the Chrome screen-recorder HUD (auto-stops a clip).",
"input": {},
"longRunning": false,
"name": "pup_recorder_close",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Close the Chrome screen-recorder HUD (auto-stops a clip).",
"timeoutSeconds": 15
},
{
"example": {},
"hint": "Opens the desktop screen-recorder UI window. OWNERSHIP: the desktop_ namespace is ab-core's; pup serves these on ab's behalf only until ab-core's native whole-desktop recorder lands (adom-bridge#143), then they leave pup. Tab recording (pup_record_*) is pup's own.",
"input": {},
"longRunning": false,
"name": "desktop_recorder_open",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [
"desktop_record_start",
"desktop_recorder_close"
],
"statusVerb": null,
"summary": "ALIAS of pup_recorder_open (routes to ab-core once its native recorder lands, adom-bridge#143).",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "Starts a full desktop screen recording (served by pup for ab-core until adom-bridge#143 lands; needs ffmpeg on the box for the duration header).",
"input": {
"outPath": "optional str"
},
"longRunning": false,
"name": "desktop_record_start",
"output": {
"success": "bool"
},
"pitfalls": [
"only one desktop recording at a time"
],
"related": [
"desktop_record_stop",
"desktop_record_status"
],
"statusVerb": null,
"summary": "ALIAS of pup_screen_record_start (routes to ab-core once its native recorder lands, adom-bridge#143).",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "Stops the desktop recording and returns the file.",
"input": {},
"longRunning": false,
"name": "desktop_record_stop",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [
"desktop_record_start",
"desktop_record_list"
],
"statusVerb": null,
"summary": "ALIAS of pup_screen_record_stop.",
"timeoutSeconds": 30
},
{
"example": {},
"hint": "Cold-start readiness probe: {ready, chromeForTestingInstalled, installing, installProgressPct}. On a fresh PC, poll this until ready:true before pup_open_window — the bridge auto-installs Chrome for Testing on its own.",
"input": {},
"longRunning": false,
"name": "pup_readiness",
"output": {
"success": "bool"
},
"pitfalls": [
"ready:false with installing:true just means Chrome for Testing is still downloading — wait + poll, do NOT treat it as an error",
"installPhase:\"failed\" → surface lastError to the user (usually network/proxy blocking the download, or low disk)"
],
"related": [
"pup_prewarm",
"pup_open_window"
],
"statusVerb": null,
"summary": "Readiness + which browser pup will drive (installed Chrome/Edge, or cached Chrome for Testing) + the full candidate list and current default. READ-ONLY; never downloads.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "Installs Chrome for Testing (the browser pup drives) WITHOUT opening a window — the warm-before-first-use path. Returns fast; poll pup_readiness for completion.",
"input": {
"setDefault": "optional bool (default true) — pin CfT as the default",
"wait": "optional bool — block until installed"
},
"longRunning": false,
"name": "pup_prewarm",
"output": {
"success": "bool"
},
"pitfalls": [
"the ~150 MB download needs network access to storage.googleapis.com",
"does not open a window — call pup_open_window once readiness reports ready:true"
],
"related": [
"pup_readiness",
"pup_open_window"
],
"statusVerb": null,
"summary": "Install Chrome for Testing WITHOUT opening a window, and pin it as the default. Use when you specifically want CfT rather than the machine's installed Chrome/Edge.",
"timeoutSeconds": 240
},
{
"example": {},
"hint": "Pin (or clear) the browser pup drives by default: chrome | edge | cft | auto (or an explicit executablePath). \"cft\" fetches Chrome for Testing then pins it. With {browser:\"chrome\", install:true} it DOWNLOADS & INSTALLS real Google Chrome on an Edge-only box, then pins it — SILENT on a normal PC; on a locked-down box (VM/managed device) it needs a Windows approval, so the bridge pops a native \"click YES on the UAC\" notification and, if it expires, re-notifies with a one-tap \"Approve now\" (all autonomous — no AI turn). Poll pup_readiness.chromeStablePhase: installing → awaiting_uac → ready. Persists across restarts; launch still spawn-verifies + falls back.",
"input": {
"browser": "\"chrome\" | \"edge\" | \"cft\" | \"auto\"",
"elevate": "optional \"auto\"(default)|true|false — auto: quiet install, prompt only if it needs admin; false: never prompt; true: go straight to the prompt",
"executablePath": "optional — pin an exact browser binary",
"install": "optional bool — with browser:\"chrome\", install real Chrome if missing"
},
"longRunning": false,
"name": "pup_use",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Pin (or clear) the browser pup drives by default: chrome | edge | cft | auto (or an explicit executablePath). \"cft\" fetches Chrome for Testing then pins it. With {browser:\"chrome\", install:true} it DOWNLOADS & INSTALLS real Google Chrome on an Edge-only box, then pins it — SILENT on a normal PC; on a locked-down box (VM/managed device) it needs a Windows approval, so the bridge pops a native \"click YES on the UAC\" notification and, if it expires, re-notifies with a one-tap \"Approve now\" (all autonomous — no AI turn). Poll pup_readiness.chromeStablePhase: installing → awaiting_uac → ready. Persists across restarts; launch still spawn-verifies + falls back.",
"timeoutSeconds": 240
},
{
"example": {},
"hint": "Send a pup window to the BACKGROUND (behind the user's windows) without stealing focus — still fully drivable. The default for open; use this to re-hide a window you foregrounded.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_lower_os_window",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Send a pup window to the BACKGROUND (behind the user's windows) without stealing focus — still fully drivable. The default for open; use this to re-hide a window you foregrounded.",
"timeoutSeconds": 15
},
{
"example": {
"foregroundReason": "user said \"show me the wiki page\""
},
"hint": "Bring a pup window to the FOREGROUND (user's screen). GATED (v1.8.70): REFUSED with foreground_reason_required unless you pass foregroundReason — a quote/paraphrase of what the user said that justifies it (min 10 chars; logged, recorded in lastAgentUpdate, auditable). Allowed ONLY when the user EXPLICITLY must SEE it (a demo, recording, \"show me\"). It STEALS focus — to just signal \"I updated this window\", use pup_alert_window (or the auto-flash), NOT raise. After the show-me: pup_lower_os_window to return it to the background. Alias: pup_focus_window. IMPORTANT: if you are foregrounding in order to CLICK a native dialog or a cross-origin FedCM/Google account chooser, do NOT raise-then-click yourself — use pup_assisted_click, which waits for the user to actually be on the window (alt-tab aware) and narrates via captions, so you never act while they are not ready.",
"input": {
"foregroundReason": "REQUIRED — why the user asked to see this window",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_raise_os_window",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Bring a pup window to the FOREGROUND (user's screen). GATED (v1.8.70): REFUSED with foreground_reason_required unless you pass foregroundReason — a quote/paraphrase of what the user said that justifies it (min 10 chars; logged, recorded in lastAgentUpdate, auditable). Allowed ONLY when the user EXPLICITLY must SEE it (a demo, recording, \"show me\"). It STEALS focus — to just signal \"I updated this window\", use pup_alert_window (or the auto-flash), NOT raise. After the show-me: pup_lower_os_window to return it to the background. Alias: pup_focus_window. IMPORTANT: if you are foregrounding in order to CLICK a native dialog or a cross-origin FedCM/Google account chooser, do NOT raise-then-click yourself — use pup_assisted_click, which waits for the user to actually be on the window (alt-tab aware) and narrates via captions, so you never act while they are not ready.",
"timeoutSeconds": 15
},
{
"example": {
"sessionId": "work",
"submit": true,
"submitReason": "confirmed the tab is on the real vendor domain I intended to sign into"
},
"hint": "Fill (and optionally submit) an HTML login form in the CURRENT tab, in the BACKGROUND — no Chrome autofill dropdown, no foregrounding, React/Vue-safe. Creds from the keychain vault (matched on the tab URL; captured automatically as you log in, or stored via credential_set / save:true) or passed explicitly. Passwords are NEVER echoed back. Vault-matched pages AUTO-FILL on load (_autoLogin on the response). SUBMIT IS REASON-GATED: submit:true requires submitReason AND makes you confirm the live domain (the refusal regurgitates the exact host so a lookalike/phishing site is caught before the secret is sent). pup_configure {autoLogin:\"off\"} disables auto-fill; {captureLogins:\"off\"} stops auto-capture.",
"input": {
"host": "optional str — override the vault host key when saving",
"password": "optional str — with username, fills these instead of the vault",
"realKeystrokes": "optional bool — type with REAL key events instead of a background .value-set. Needed for React-controlled MASKED fields (Gusto/Keycloak SSO) that ignore .value and would submit an empty password. It briefly FOREGROUNDS the window (real keystrokes only register on-screen). Use when a normal fill returned filledPassword:false / reactMaskedFieldSuspected, or when the login-recipe for the site says so.",
"save": "optional bool — with explicit creds, store them (OS keychain) so next time is automatic",
"sessionId": "optional str — omit to target the window your own thread owns",
"submit": "optional bool — submit after filling; REQUIRES submitReason",
"submitReason": "required WITH submit:true — why you are confident the CURRENT domain is the correct, intended site to send these credentials to (min 10 chars; the refusal shows you the live host to confirm; logged, auditable)",
"username": "optional str"
},
"longRunning": false,
"name": "pup_login",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Fill (and optionally submit) an HTML login form in the CURRENT tab, in the BACKGROUND — no Chrome autofill dropdown, no foregrounding, React/Vue-safe. Creds from the keychain vault (matched on the tab URL; captured automatically as you log in, or stored via credential_set / save:true) or passed explicitly. Passwords are NEVER echoed back. Vault-matched pages AUTO-FILL on load (_autoLogin on the response). SUBMIT IS REASON-GATED: submit:true requires submitReason AND makes you confirm the live domain (the refusal regurgitates the exact host so a lookalike/phishing site is caught before the secret is sent). pup_configure {autoLogin:\"off\"} disables auto-fill; {captureLogins:\"off\"} stops auto-capture.",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "List saved logins (host + username only; passwords are in the OS keychain and NEVER returned). pup captures these automatically as you sign into sites and auto-fills them in the background on return visits.",
"input": {},
"longRunning": false,
"name": "pup_credentials",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "List saved logins (host + username only; passwords are in the OS keychain and NEVER returned). pup captures these automatically as you sign into sites and auto-fills them in the background on return visits.",
"timeoutSeconds": 10
},
{
"example": {
"host": "github.com",
"reason": "signing into GitHub in my own browser to open a PR for the user"
},
"hint": "Reveal ONE saved login (username + password) to a LOCAL caller on the desktop, gated by a sticky consent toast the user must click. One host per call, never bulk. A relayed (cloud container) call is refused with relay_forbidden: from a cloud thread use pup_login instead, which signs the site in inside a pup window without the secret ever leaving the vault. The secret is returned ONCE and must never be logged or echoed.",
"input": {
"host": "required str — the site, e.g. \"github.com\"",
"reason": "required str (min 10 chars) — shown to the user on the consent toast; say what you will do with it"
},
"longRunning": false,
"name": "pup_credential_reveal",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Reveal ONE saved login (username + password) to a LOCAL caller on the desktop, gated by a sticky consent toast the user must click. One host per call, never bulk. A relayed (cloud container) call is refused with relay_forbidden: from a cloud thread use pup_login instead, which signs the site in inside a pup window without the secret ever leaving the vault. The secret is returned ONCE and must never be logged or echoed.",
"timeoutSeconds": 130
},
{
"example": {},
"hint": "Store a payment card in the OS-keychain card vault under a nickname. Ask the USER for the details — never harvest them from a page. Validates Luhn + expiry + cvv. No verb ever returns the number or CVV afterward.",
"input": {
"cvv": "required 3-4 digits",
"expiry": "required MM/YY",
"name": "optional cardholder name",
"nickname": "required str, e.g. \"adom-amex\"",
"number": "required str"
},
"longRunning": false,
"name": "pup_card_set",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Store a payment card in the OS-keychain card vault under a nickname. Ask the USER for the details — never harvest them from a page. Validates Luhn + expiry + cvv. No verb ever returns the number or CVV afterward.",
"timeoutSeconds": 15
},
{
"example": {},
"hint": "List saved payment cards: nickname, brand, last4, expiry, cardholder only. The number and CVV never leave the keychain.",
"input": {},
"longRunning": false,
"name": "pup_cards",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "List saved payment cards: nickname, brand, last4, expiry, cardholder only. The number and CVV never leave the keychain.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "Remove a saved card from the keychain + index by nickname.",
"input": {
"nickname": "required str"
},
"longRunning": false,
"name": "pup_card_delete",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Remove a saved card from the keychain + index by nickname.",
"timeoutSeconds": 10
},
{
"example": {
"amount": "$350",
"merchant": "venturedallas.com",
"nickname": "adom-amex"
},
"hint": "Fill a saved card into the checkout page of a pup window WITHOUT the digits ever reaching you: pup types them into the card fields (walking payment-processor iframes like Stripe) and returns booleans. EVERY fill is gated by a desktop approval toast naming merchant, amount and last4 — the user authorizes the specific charge in the moment. Pass merchant+amount so the toast is honest. Allowed from cloud threads (the human click is the gate). After ok:true, screenshot to verify, then submit.",
"input": {
"amount": "recommended str, e.g. \"$350\"",
"merchant": "recommended str — shown on the approval toast",
"nickname": "required str",
"window": "optional (defaults to your thread's window)"
},
"longRunning": false,
"name": "pup_fill_card",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Fill a saved card into the checkout page of a pup window WITHOUT the digits ever reaching you: pup types them into the card fields (walking payment-processor iframes like Stripe) and returns booleans. EVERY fill is gated by a desktop approval toast naming merchant, amount and last4 — the user authorizes the specific charge in the moment. Pass merchant+amount so the toast is honest. Allowed from cloud threads (the human click is the gate). After ok:true, screenshot to verify, then submit.",
"timeoutSeconds": 130
},
{
"example": {
"hostFilter": [
"snapeda",
"ultralibrarian",
"digikey"
]
},
"hint": "Seed pup's vault from the user's OWN saved Chrome/Edge/Brave passwords, so pup can sign in as them on sites they already use (vendor CAD portals, etc). Runs the SYSTEM-elevated decrypt LOCALLY — the user approves ONE consent dialog + ONE Windows UAC prompt on the desktop (a cloud/relay caller cannot do this; only pup, a local bridge, can ask). Merges the identity-tagged rows into the keychain vault and DROPS the plaintext. Returns COUNTS ONLY. hostFilter narrows the import to matching hosts (surgical, e.g. [\"snapeda\",\"digikey\"]); omit to import everything saved. Pair with pup_import_scan (read-only preview of how many logins exist).",
"input": {
"browsers": "optional str[] subset of [\"chrome\",\"edge\",\"brave\"] (default: all found)",
"hostFilter": "optional str or str[] — only import logins whose host contains one of these (surgical import)"
},
"longRunning": false,
"name": "pup_import_browser_logins",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Seed pup's vault from the user's OWN saved Chrome/Edge/Brave passwords, so pup can sign in as them on sites they already use (vendor CAD portals, etc). Runs the SYSTEM-elevated decrypt LOCALLY — the user approves ONE consent dialog + ONE Windows UAC prompt on the desktop (a cloud/relay caller cannot do this; only pup, a local bridge, can ask). Merges the identity-tagged rows into the keychain vault and DROPS the plaintext. Returns COUNTS ONLY. hostFilter narrows the import to matching hosts (surgical, e.g. [\"snapeda\",\"digikey\"]); omit to import everything saved. Pair with pup_import_scan (read-only preview of how many logins exist).",
"timeoutSeconds": 190
},
{
"example": {
"dryRun": true
},
"hint": "Delete LEAKED isolated profile directories — the iso-* throwaway jars minted by isolated:true opens (and by wikiView:public before 2.0.132, when the public view moved to the server-side ?view=public param) whose window is long gone (they used to pile up, 100s per machine). Only removes an iso-* dir that no live session or session file owns, that no Chrome is holding, and that is >15 min old; durable jars (adom-you, named profiles) are NEVER touched. Runs automatically every 15 min too. dryRun:true previews the list without deleting.",
"input": {
"dryRun": "optional bool — preview which iso-* profiles would be removed, delete nothing"
},
"longRunning": false,
"name": "pup_reap_profiles",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Delete LEAKED isolated profile directories — the iso-* throwaway jars minted by isolated:true opens (and by wikiView:public before 2.0.132, when the public view moved to the server-side ?view=public param) whose window is long gone (they used to pile up, 100s per machine). Only removes an iso-* dir that no live session or session file owns, that no Chrome is holding, and that is >15 min old; durable jars (adom-you, named profiles) are NEVER touched. Runs automatically every 15 min too. dryRun:true previews the list without deleting.",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "MOVE this pup window's page into the user's Hydrogen workspace: the active tab's URL is handed to Hydrogen (ah) on this machine via its Browser Picker (webview by default, honoring the user's per-domain choice), then the pup window closes — its owner initiated the move. keepWindow:true keeps the pup window open too. Needs Hydrogen running locally (hydrogen_unreachable otherwise; the window is left untouched on failure). Cloud Hydrogen (hc) is not yet supported.",
"input": {
"keepWindow": "optional bool — hand the URL over but keep the pup window open",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_move_to_workspace",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "MOVE this pup window's page into the user's Hydrogen workspace: the active tab's URL is handed to Hydrogen (ah) on this machine via its Browser Picker (webview by default, honoring the user's per-domain choice), then the pup window closes — its owner initiated the move. keepWindow:true keeps the pup window open too. Needs Hydrogen running locally (hydrogen_unreachable otherwise; the window is left untouched on failure). Cloud Hydrogen (hc) is not yet supported.",
"timeoutSeconds": 25
},
{
"example": {
"dryRun": true
},
"hint": "DESTRUCTIVE — cleanly remove pup's WHOLE footprint from this machine: the HKCU AppUserModelId Adom.Pup registry keys, all staged extensions, ALL pup profiles + sessions, the OS-keychain credential vault, pup-settings.json, the badge-debug temp dir, and the jump-list launcher. ALWAYS preview first with dryRun:true (removes nothing, returns the plan). To actually remove, pass confirm:\"uninstall\". keepCredentials:true preserves the saved-login vault; keepProfiles:true preserves profiles/sessions. Chrome-for-Testing + firewall rules are SHARED and left alone unless removeChrome:true / removeFirewallRules:true. Closes every window + quits every browser first to release profile locks. (The bridge itself is managed by Adom Bridge — remove pup from Bridge to stop it re-seeding.)",
"input": {
"confirm": "required str \"uninstall\" to actually remove",
"dryRun": "optional bool — preview the removal plan without removing anything (do this first)",
"keepCredentials": "optional bool — keep the saved-login vault",
"keepProfiles": "optional bool — keep pup profiles + sessions",
"removeChrome": "optional bool — also delete the Chrome-for-Testing install (shared; default keep)",
"removeFirewallRules": "optional bool — also remove the CfT firewall rules (needs admin)"
},
"longRunning": false,
"name": "pup_uninstall",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "DESTRUCTIVE — cleanly remove pup's WHOLE footprint from this machine: the HKCU AppUserModelId Adom.Pup registry keys, all staged extensions, ALL pup profiles + sessions, the OS-keychain credential vault, pup-settings.json, the badge-debug temp dir, and the jump-list launcher. ALWAYS preview first with dryRun:true (removes nothing, returns the plan). To actually remove, pass confirm:\"uninstall\". keepCredentials:true preserves the saved-login vault; keepProfiles:true preserves profiles/sessions. Chrome-for-Testing + firewall rules are SHARED and left alone unless removeChrome:true / removeFirewallRules:true. Closes every window + quits every browser first to release profile locks. (The bridge itself is managed by Adom Bridge — remove pup from Bridge to stop it re-seeding.)",
"timeoutSeconds": 60
},
{
"example": {},
"hint": "Nudge the user about a pup window WITHOUT stealing focus — on Windows it flashes the taskbar button; on macOS (no taskbar, and no API to bounce another app's Dock tile) it unhides the window at its z-position and posts an AD toast whose click focuses it. Same contract on both, so call it identically; just never tell a Mac user to look for a flashing icon. NOTE (v1.8.23): mutating verbs already AUTO-FLASH (debounced, one per ~5s burst per window) so the user always knows the agent touched a window — use this for an explicit end-of-task \"it's ready\" nudge on top of that. STRONGLY prefer this (or the auto-flash) over pup_raise_os_window, which steals focus and can leak a mid-typed keystroke into the page.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"stop": "optional bool — CLEAR the highlight instead of flashing"
},
"longRunning": false,
"name": "pup_alert_window",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Nudge the user about a pup window WITHOUT stealing focus — on Windows it flashes the taskbar button; on macOS (no taskbar, and no API to bounce another app's Dock tile) it unhides the window at its z-position and posts an AD toast whose click focuses it. Same contract on both, so call it identically; just never tell a Mac user to look for a flashing icon. NOTE (v1.8.23): mutating verbs already AUTO-FLASH (debounced, one per ~5s burst per window) so the user always knows the agent touched a window — use this for an explicit end-of-task \"it's ready\" nudge on top of that. STRONGLY prefer this (or the auto-flash) over pup_raise_os_window, which steals focus and can leak a mid-typed keystroke into the page.",
"timeoutSeconds": 15
},
{
"example": {
"html": "<h1>Café</h1>",
"sessionId": "work"
},
"hint": "Render a local HTML string in the tab via page.setContent — UTF-8-correct (a data: URL mojibakes accented chars without an explicit charset). Great for previewing generated markup without a temp file. Auto-flashes the window.",
"input": {
"html": "required HTML string",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"silent": "optional bool — suppress the auto-flash",
"updateNote": "optional note for lastAgentUpdate",
"waitUntil": "optional (domcontentloaded default)"
},
"longRunning": false,
"name": "pup_render_html",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Render a local HTML string in the tab via page.setContent — UTF-8-correct (a data: URL mojibakes accented chars without an explicit charset). Great for previewing generated markup without a temp file. Auto-flashes the window.",
"timeoutSeconds": 30
},
{
"example": {},
"hint": "List all open pup sessions + their tabs (NOT a readiness check — use pup_readiness for that).",
"input": {},
"longRunning": false,
"name": "pup_status",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "List all open pup sessions + their tabs (NOT a readiness check — use pup_readiness for that).",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "List every open session/window with its tabs.",
"input": {},
"longRunning": false,
"name": "pup_list_windows",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "List every open session/window with its tabs.",
"timeoutSeconds": 10
},
{
"example": {
"expr": "document.querySelector(\"#userId\").value",
"frame": "logonbox",
"sessionId": "work"
},
"hint": "pup_eval accepts frame:\"<name|url-substring|index>\" to run inside an IFRAME (login forms usually live in one). Cross-origin frames work. Omit for the top document; a bad value returns frame_not_found WITH the list of frames in the tab.",
"input": {
"expr": "required str",
"frame": "optional str",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_eval_frame_note",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "pup_eval accepts frame:\"<name|url-substring|index>\" to run inside an IFRAME (login forms usually live in one). Cross-origin frames work. Omit for the top document; a bad value returns frame_not_found WITH the list of frames in the tab.",
"timeoutSeconds": 20
},
{
"example": {
"sessionId": "work"
},
"hint": "Make a session the active one (for verbs that default to active).",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_switch_window",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Make a session the active one (for verbs that default to active).",
"timeoutSeconds": 10
},
{
"example": {
"sessionId": "work"
},
"hint": "List the tabs in a session.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_list_tabs",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "List the tabs in a session.",
"timeoutSeconds": 10
},
{
"example": {
"sessionId": "work",
"tabId": "tab-2"
},
"hint": "Activate a tab WITHIN its session/window (idempotent — safe to call when the tab is already active). Does NOT raise a background window to the user's screen: the tab becomes the window's visible tab wherever the window is, and the taskbar auto-flash tells the user something changed. Also self-heals the window (re-park if a bug ever stranded it off-screen) and refreshes the Adom taskbar badge — good citizenship for long-lived shared windows.",
"input": {
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"silent": "optional bool",
"tabId": "required str",
"updateNote": "optional str"
},
"longRunning": false,
"name": "pup_switch_tab",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Activate a tab WITHIN its session/window (idempotent — safe to call when the tab is already active). Does NOT raise a background window to the user's screen: the tab becomes the window's visible tab wherever the window is, and the taskbar auto-flash tells the user something changed. Also self-heals the window (re-park if a bug ever stranded it off-screen) and refreshes the Adom taskbar badge — good citizenship for long-lived shared windows.",
"timeoutSeconds": 10
},
{
"example": {
"sessionId": "work"
},
"hint": "FULL-resolution page screenshot (NOT downscaled — for saving to disk, NOT for Read: it can exceed Claude's image limit). Use pup_screenshot for AI-readable shots.",
"input": {
"fullPage": "optional bool",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_screenshot_full_res",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "FULL-resolution page screenshot (NOT downscaled — for saving to disk, NOT for Read: it can exceed Claude's image limit). Use pup_screenshot for AI-readable shots.",
"timeoutSeconds": 30
},
{
"example": {
"sessionId": "work"
},
"hint": "Console errors + failed network requests for a session/tab (clears by default).",
"input": {
"clear": "optional bool (default true)",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)",
"tabId": "optional str"
},
"longRunning": false,
"name": "pup_errors",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Console errors + failed network requests for a session/tab (clears by default).",
"timeoutSeconds": 10
},
{
"example": {
"ms": 500,
"sessionId": "work"
},
"hint": "Wait N ms (or for a selector) before the next step.",
"input": {
"ms": "optional int",
"selector": "optional str",
"sessionId": "optional str — OMIT IT: zero-id addressing resolves your --ai-thread name to your own window. Pass a window label only when one thread runs several windows (`window` is the new name for this param; sessionId is the legacy alias)"
},
"longRunning": false,
"name": "pup_wait",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Wait N ms (or for a selector) before the next step.",
"timeoutSeconds": 60
},
{
"example": {},
"hint": "Recover orphaned sessions: reconnect dropped CDP sockets + rebuild sessions from window titles. Pass adoptOrphans:true to also adopt untagged tabs.",
"input": {
"adoptOrphans": "optional bool"
},
"longRunning": false,
"name": "pup_rescan",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Recover orphaned sessions: reconnect dropped CDP sockets + rebuild sessions from window titles. Pass adoptOrphans:true to also adopt untagged tabs.",
"timeoutSeconds": 30
},
{
"example": {},
"hint": "Close ALL pup sessions + windows at once (destructive). NOTE: `{}` here does NOT mean \"the active session\" the way it does on other session-scoped verbs — with no args this closes EVERY window, across every AI thread on the machine, with no confirmation. To close ONE window use pup_close_window {sessionId}. Pass {sessionId} here only if you genuinely mean that one session.",
"input": {},
"longRunning": false,
"name": "pup_close",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Close ALL pup sessions + windows at once (destructive). NOTE: `{}` here does NOT mean \"the active session\" the way it does on other session-scoped verbs — with no args this closes EVERY window, across every AI thread on the machine, with no confirmation. To close ONE window use pup_close_window {sessionId}. Pass {sessionId} here only if you genuinely mean that one session.",
"timeoutSeconds": 20
},
{
"example": {},
"hint": "ALIAS of pup_screen_record_status.",
"input": {},
"longRunning": false,
"name": "desktop_record_status",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "ALIAS of pup_screen_record_status.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "ALIAS of pup_screen_record_list.",
"input": {},
"longRunning": false,
"name": "desktop_record_list",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "ALIAS of pup_screen_record_list.",
"timeoutSeconds": 10
},
{
"example": {},
"hint": "ALIAS of pup_recorder_close.",
"input": {},
"longRunning": false,
"name": "desktop_recorder_close",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "ALIAS of pup_recorder_close.",
"timeoutSeconds": 15
},
{
"example": {
"taskbarGrouping": "grouped"
},
"hint": "Get/set user-facing pup preferences (persisted across bridge updates). taskbarGrouping: \"split\" (default — one taskbar button PER WINDOW, each badged with its own tab count; best for telling AI threads apart) | \"grouped\" (all pup windows stack under ONE \"Adom Pup\" button, badge shows window count; tidy taskbar). Applies to live windows immediately. Ask the USER which they prefer before changing it — this is their taskbar. WINDOWS ONLY: macOS has no taskbar, so the setting is stored but INERT there; the reply carries platform + taskbarSupported so branch on those, not on this text.",
"input": {
"autoLogin": "optional \"on\"|\"off\" — auto-fill a vault-matched login form on page load (fill only, never submits), on by default",
"overlaySize": "optional \"50\"|\"100\" — how big the favicon badge is drawn on the taskbar button. \"50\" (the DEFAULT) draws it at half size so it stays clear of the thread tile's bottom line of text; \"100\" is the older, larger badge",
"reportIssues": "optional \"on\"|\"off\" — pup's bug-report invitation (_reportIssues), on by default",
"taskbarActivity": "optional \"progress\"|\"flash\"|\"off\" — how pup signals it is working on a window, on that window's taskbar button: a determinate progress bar sized to the operation's running-average time (default), the old orange flash, or nothing. Replaces the former openFlash/autoFlash/agentActivity toggles.",
"taskbarGrouping": "optional \"split\"|\"grouped\""
},
"longRunning": false,
"name": "pup_configure",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [],
"statusVerb": null,
"summary": "Get/set user-facing pup preferences (persisted across bridge updates). taskbarGrouping: \"split\" (default — one taskbar button PER WINDOW, each badged with its own tab count; best for telling AI threads apart) | \"grouped\" (all pup windows stack under ONE \"Adom Pup\" button, badge shows window count; tidy taskbar). Applies to live windows immediately. Ask the USER which they prefer before changing it — this is their taskbar. WINDOWS ONLY: macOS has no taskbar, so the setting is stored but INERT there; the reply carries platform + taskbarSupported so branch on those, not on this text.",
"timeoutSeconds": 15
},
{
"example": {},
"hint": "This list — the bridge's verbs + schemas + hints, for AD's Verbs tab. Read it once to learn the surface.",
"input": {},
"longRunning": false,
"name": "pup_describe",
"output": {
"success": "bool"
},
"pitfalls": [],
"related": [
"pup_status"
],
"statusVerb": null,
"summary": "This list — the bridge's verbs + schemas, for AD's Verbs tab.",
"timeoutSeconds": 10
}
]
}