app
Pup - Puppeteer Bridge
Public Made by Adomby adom
pup is the AI's own browser: a real, full Chrome on the user's desktop that the AI fully controls (a sandbox, not the user's signed-in browser). Rides Bridge; pup_* verbs open windows and tabs, navigate, screenshot, and eval JS.
Interactive-surface phase 1+2 core (plan: docs/PLAN-interactive-surface.md). Annotation captures are now TIGHT-CROPPED to the drawn strokes plus a 48px margin instead of the whole browser view (John: if the user wants the whole view they'll draw a circle around it), Photoshop-style tool cursors with the pen carrying a live swatch of the selected color, a quick-capture Auto mode that fires the moment the mouse lifts, and the clipboard-first return path: every capture lands in the Windows clipboard as image plus text JSON sidecar together via a .NET DataObject helper so one paste into any AI chat carries both, with a caption bar baked under the crop and an iTXt metadata chunk inside the PNG so an image-only paste still carries context. An in-page toast shows a thumbnail of the exact crop grabbed. Also: USER_CALLERS set replaces the four exact-string user-taskbar-menu compares (the toolbar extension's user-toolbar caller joins it), and the toolbarExtension settings family lands ahead of the extension
John Lauer
·
fbc1bd2
·
21h ago
Update 1 file(s)
John Lauer
·
a3bd8fe
·
21h ago
Annotation and snipping land in pup (John: claude desktop can annotate in its browser, add it to pup, and build in a screenshot snippet like shift+win+s). New pup_annotate verb plus an Annotate this page task on every window's jump list: an in-page overlay with pen, arrow, box, text, color cycling, undo, and a Snip tool whose marquee captures just that region immediately, exactly the win+shift+s flow. Done captures a PNG and deliberately leaves the drawing in the DOM, because pup windows are thread-owned: the annotation is a message, and the owning AI thread's next screenshot shows exactly what the human circled. Captures store under screenshots/ and surface as session lastAnnotation; a caption confirms the handoff. jlAnnotate sub-setting, default on
John Lauer
·
2a73c72
·
22h ago
Update 1 file(s)
John Lauer
·
0e01196
·
1d ago
Update 1 file(s)
John Lauer
·
4d28031
·
1d ago
Switch to public view on a shared-profile window no longer logs every thread out. John asked what should happen clicking the jump-list view toggle on a multi-tab window; the code answer was a browser-wide cookie wipe (CDP clearBrowserCookies) that silently signed out every window of every thread, then reloaded only the active tab, because the shared-profile guard tested the legacy adom-wiki-authed profile name and never matched today's shared adom-you. The guard now uses ground truth (any other live session on the same profile, plus the known shared names), so a shared-profile public switch takes the tab-preserving relaunch path: the whole window with all its tabs moves to a logged-out profile and no other window is touched. Also ships the quieted 60s overlay re-assert logging staged earlier
John Lauer
·
ecd8873
·
1d ago
Update 1 file(s)
John Lauer
·
aacd96d
·
1d ago
Overlay badges can no longer silently vanish, the bare taskbar tile John caught that my log-trusting audit missed: the taskbar progress cycle (and other shell-side events) can clear a button's overlay, but pup's paint memory survived it, so the enforcer saw a painted window and never repainted, bare on screen while green in the logs. Windows offers no way to query overlay state, so the fix treats it as write-only: every progress change voids the paint memory (the 4s enforcer sweep repaints), and a 60s per-window ground-truth re-assert repaints unconditionally so memory can never drift from the screen for more than a minute. Also dedupes the sibling-favicon log line that spammed on every re-resolve
John Lauer
·
bf538f9
·
1d ago
Update 2 file(s)
John Lauer
·
3bf4453
·
1d ago
Close the whole window, not just the bound tabs, the last ghost-window wonk the mimic ralph surfaced: recovery binds one tab per session and the sibling-tab rescan runs later, so a pup_close_window issued soon after a bridge respawn closed 1 of N tabs, declared the session closed, and left the OS window alive as an orphan that pup later adopted as a strange auto-named adom-you session. pup_close_window now collects the CDP windowId of every bound tab and closes every page living in those windows, bound or not, with a shared-profile guard so a page tracked by any other session is never touched
John Lauer
·
81c080b
·
1d ago
Update 2 file(s)
John Lauer
·
d2821fe
·
1d ago
Stop handle theft between same-page windows, the wonk the hardened mimic ralph caught red-handed: mimic windows and a second hd-publish window stole real windows' taskbar handles after a respawn. Three causes fixed. The natural-title resolver asked for the WRONG title (pup's activeTabId bookkeeping says first tab while Chrome's window title mirrors the last-opened visible tab), making a session uniquely match someone else's window; it now asks Chrome which tab is actually visible. A title shared by two pup windows is now refused outright, counted over all pup rows BEFORE ownership exclusions, because excluding the true owner's row is exactly how a theft looked unique. And a persisted-claims map now loads every session file's handle at recovery start, so a handle is protected before its owner's session even finishes recovering, closing the recovery-storm race. The mimic harness now also asserts the real windows and never resets its collision map so cross-session theft can never self-grade OK again
John Lauer
·
f308e17
·
1d ago
Recovered windows finally re-resolve their taskbar identity, read-only. The mimic ralph proved every window went bare after a respawn: the persisted-handle continuity check was silent, geometry cannot tell identical parked windows apart, and the off-screen re-capture failed silently on this box because Chrome clamps off-screen coordinates so the absolute-position match never hit (and its restore dumped windows at 0,0, itself visible wonk). Four changes: enum rows now carry the native window title; a new natural-title resolver matches each session's active-tab title against pup-owned windows only (pid-fenced so the user's own Chrome can never match, exactly-one or refuse, nothing written anywhere); the re-capture identifies the moved window by bounds change instead of absolute position (clamp-proof) and restores the exact original rect; and the continuity/recovery paths now log their outcomes so silent success or failure is visible
John Lauer
·
f532ef3
·
1d ago
Fix the two wonks the mimic ralph reproduced from John's real 3-thread workload. One: after any bridge respawn every recovered window lost its taskbar identity (no handle, no overlay, unbrandable) because all four ownership proofs are dead for a recovered window, so the perfectly good persisted hwnd was discarded and the wiggle fallback could not disambiguate the shared profile. Recovery now records Chrome's persisted pid next to the restored hwnd, and hwndBelongsToPup accepts the pair (handle still owned by the exact process it was recorded under, and Chrome outlives pup respawns) as proof by continuity. Two: windows randomly ended up frozen with a 3-task jump list missing both view toggles, because a wiki window's categorized appId can commit before its login view resolves and the freeze locked that incomplete menu forever; wiki-category windows now freeze only once the view tasks are actually in the menu. Found by dev-skills/pup-taskbar-identity/ralph_mimic.sh, the new harness that replays John's observed workload including the respawn-recovery leg
John Lauer
·
2293e96
·
1d ago
Add an Open pup dashboard task to every pup taskbar jump list (John's ask): one right-click opens the live dashboard mapping every pup window and tab to its owning AI thread, reusing the one dashboard window on repeat clicks. Routed through the v2.0.41 direct-callback launcher like every other task. New jlDashboard sub-setting (default on) under Jump lists in the settings dialog, wired into the dedupe key and the settings refresh path so toggling it updates existing windows immediately
John Lauer
·
ad1ecd1
·
1d ago
Update 2 file(s)
John Lauer
·
9e37cdc
·
1d ago
Jump-list tasks now call pup directly (John: be way smarter about how to call back into ab for the jump lists; should pup talk to itself when it is its own bridge). Answer: yes for pup verbs. Old tasks set no target so ab supplied the program (its bundled CLI), an exe path pup neither controls nor verifies and exactly what the CLI rename broke. Each task now carries target=powershell.exe plus a pup-owned launcher script that reads pup's own loopback port from a discovery file pup rewrites on every bind, POSTs the verb straight to pup (pup to pup, no ab hop, no CLI, no stale path), and only falls back to the resolved adom-bridge-cli.exe (which wakes pup via ab) if the direct hit fails because pup idled. JSON args ride as base64 so nothing mangles through the shell-link to powershell argv reparse. No ab change needed: the per-task target field already existed
John Lauer
·
4c0120e
·
1d ago
Fix jump-list items doing nothing (John: Close ALL and other menu items don't work): the bundled CLI renamed from adom-desktop-cli.exe in the Adom Desktop folder to adom-bridge-cli.exe in the Adom Bridge folder, but pupRelaunchCommand hardcoded the OLD path, so every jump-list task, taskbar header click, and pinned launch invoked a missing exe and silently no-opped (verified live: old path gone, new path exists). The bridge runs on the desktop so it now resolves the real exe from disk, Bridge name first with a legacy fallback, cached
John Lauer
·
a26d201
·
1d ago
New dev skill pup-taskbar-identity: the birth-hwnd capture architecture (serialized set-diff, position-independent) and the mandatory ralph test (ralph_icons.sh) that must pass before claiming any taskbar-identity fix; records the ban on position-matching and log-only proof. Baseline: two warm 18-window runs, 0 failures each
John Lauer
·
02d064f
·
1d ago
Remove the temporary birth-capture diagnostics now that the raw-Chrome-icon regression is root-caused and fixed (2.0.37 routes every window through the birth path, 2.0.38 makes capture position-independent and serialized). Verified live: four windows including three opened in parallel each got a distinct OS handle, a correct AUMID teal tile, and an overlay badge, with zero collisions and zero stamp failures
John Lauer
·
7895c8b
·
1d ago
Position-independent, serialized birth-hwnd capture, the real fix: Chrome clamps our -32000 off-screen birth coordinate on-screen on some boxes, so identifying the new window by position fails (newOff was always 0). Now a global birth lock serializes window creation so the set-diff sees EXACTLY ONE new OS handle regardless of where Chrome placed it - that handle is the window, unambiguously, with no position or pid dependency. Combined with 2.0.37 routing the first window per profile through this same path, every pup window on Windows now gets a reliable unique handle, so AUMID and overlay paint and no window shows a raw Chrome button
John Lauer
·
0af3e7c
·
1d ago
THE root cause of the raw-Chrome taskbar icons: only the 2nd-plus window on a profile went through the birth-capture path that assigns an OS hwnd; the FIRST window on a profile used browser.newPage() which captures no handle, so after 2.0.24 removed the title-tag fallback that first window was permanently unresolvable and showed a raw Chrome button with no AUMID and no overlay. Now every pup window on Windows is created through createPageInNewWindow (off-screen birth + set-diff capture), so all of them get a reliable, unique handle. Keeps the 2.0.36 diagnostics one more build to confirm
John Lauer
·
5518892
·
1d ago
Temporary diagnostic instrumentation on the birth-capture block to find why hwnd resolution stopped producing results (logs fresh/profile/beforeHwnds, per-iter rows/offscreen/newOff counts, and any thrown exception) - to be removed once the root cause is found
John Lauer
·
b59b78d
·
1d ago
Make the 2.0.34 set-diff birth capture actually resolve under concurrency: widen the off-screen birth spacing from 40px to 220px so disambiguating concurrent births by nearest-birthLeft is unambiguous against Chrome placement jitter (the 18px tolerance was too tight and left every concurrent birth AMBIGUOUS with nothing stamped; 60px had been too loose and cross-wired). New windows are identified by set-diff, then the one nearest my unique birthLeft is mine
John Lauer
·
b087cb7
·
1d ago
Fix cross-wired taskbar identity John caught (fusion and nb resolved to the SAME hwnd, so one thread stamped its AUMID onto the other's window and the loser stayed a grouped raw-Chrome button while a pup tile showed no overlay): the birth-time hwnd capture is now a SET-DIFF (snapshot window handles before createTarget, the NEW off-screen handle not present before and not already owned by any session is ours by construction) instead of a coordinate match whose 60px tolerance overlapped the 40px birth spacing; concurrent births disambiguate by the unique birthLeft with an 18px tolerance; and a hard guard rejects any handle already owned by another live session at every resolution path (birth, geometry, off-screen re-capture) so two windows can never share one handle
John Lauer
·
ab4ae56
·
1d ago
Let the off-screen re-capture run even while a window is in the geometry-resolution backoff (the backoff only suppresses the geometry hammering, not the definitive re-capture that actually fixes the bare window), with a 30s per-window cooldown so it moves the window at most once per half-minute
John Lauer
·
ef8089f
·
1d ago
Self-heal bare BACKGROUND pup windows that have no birth handle (opened before the 2.0.31 fix, or re-attached by recovery/drag-out) on a crowded shared profile where geometry cannot disambiguate: as a last resort the resolver briefly moves the window's own CDP target to a unique far-off-screen slot, enumerates to grab the window now at that exact coordinate (unambiguous identity by construction), then restores it on-screen at z-bottom and re-parks. Invisible because the window is already background z-bottom, and never done to a window the user is using. Gives an on-screen window the same reliable handle a birth-time window gets, so its AUMID and overlay finally paint
John Lauer
·
1c64900
·
1d ago
Fix raw-Chrome taskbar icons on pup windows, the regression from removing the title tag: killing the title tag in 2.0.24 silently removed the shared-profile fallback that BOTH the identity stamp (titleContains) and hwndBelongsToPup (v1.9.350 title-ownership proof) relied on, so any window whose hwnd did not resolve got no AUMID and no overlay and showed a raw flashing Chrome button. Fixes: (1) birth-time hwnd capture now matches the window by its UNIQUE off-screen birth position instead of by pid membership, which was empty for the shared adom-you Chrome process whose real pid is untracked; (2) hwndBelongsToPup now trusts a birth-captured handle as proof of ownership by construction, no title and no pid tracking needed, and learns the pid so sibling windows on the shared process pass instantly. Identity and overlay no longer depend on the title tag at all
John Lauer
·
d996590
·
1d ago
Fix the jump-list tasks broken by the 2.0.28 ownership gate: a click on a pup window's own taskbar jump-list is the USER operating their own window (caller aiThread user-taskbar-menu) and is always sanctioned, so it bypasses the ownership gate, the omitted-sessionId active-window resolution, and the dead-session hard error; and pup_close with no sessionId is the global close-all by design and is never gated or resolved to the active window. The Close ALL task, the Owned-by info card, and both wiki view-switch tasks all work again
John Lauer
·
0345e5f
·
1d ago
Close issue 42, the wiki sign-in race across shared-profile pup windows: auto-sign from the desktop wiki token now runs for the shared adom-you profile on ANY adom URL that is not the deliberately-anonymous public or isolated view, not only when wikiView:authed is explicitly requested, so a fresh window whose shared cookie has not landed yet no longer paints signed-out while its siblings show signed-in; it fires only on a definite 401 (never a probe timeout) so an already-signed-in window is never re-navigated, and it schedules an overlay repaint so the taskbar hover thumbnail drops any cached signed-out frame
John Lauer
·
bc5e353
·
1d ago
Close issue 41, the isolation hole the nb thread caught that masqueraded as a cross-thread takeover: a verb naming a DEAD sessionId now hard-errors with session_not_found and the live-session list instead of silently falling back to another thread's active window, and per John's ai-thread model the activeSessionId implication is deleted from every session-targeting verb: omitted sessionId resolves to the CALLER THREAD's own window (the shared ai-thread-slug keying pup_open_window uses, or the single window the thread owns by explicit name), with a teaching error when the thread has none or several; the ownership gate also now covers resolved targets, not just explicitly named ones
John Lauer
·
e6bb3c1
·
1d ago
The PowerShell deletion on ab 2.0.16 native verbs, closing the ab64 commitment: z-order, foreground reads, user-idle, window enumeration by pid and class, hwnd owner validation, parent-pid checks, send-to-back, lower-by-pid, and the taskbar attention clear are all precompiled-Rust ab calls now (roughly 20ms each versus 300ms runtime-compiled PowerShell spawns), the EnumWindows resolver and its temp-file EBUSY class are gone, the zero-caller osMinimizeToBackground and osBackgroundWatchdog are deleted, the synchronous PowerShell runner itself is deleted with zero callers remaining, internal identifiers adCommand and adPayload renamed to abCommand and abPayload, and the user-foreground doctrine got the fix John's question exposed: an ever-user-raised window stays hands-off for as long as it remains OS-foreground with no ten-minute clock, the recency window only applies once the user has left. Five scripts remain by design: the focus-raise dance x3 (works today, wishlisted for a native raise verb), base-icon extraction, and the credential import scan, all async-only
John Lauer
·
269fb91
·
1d ago
New dev skill pup-user-foreground: the settled doctrine for the user-taskbar-click vs pup-demotion fight we relitigated twenty times - the contract, the recent-input heuristic inside the demotion primitive, the guard list, the ban list, the hardening history table, and the acceptance test
John Lauer
·
070a50b
·
1d ago
Stop fighting the user for the window: the post-open re-assert timers called the z-bottom primitive with force (needed for Chrome PDF self-activation pops) which also demoted a window the USER had just raised from the taskbar, because the session-flag guards lag the click by seconds. The primitive now checks GetLastInputInfo in the same PowerShell pass: OS-foreground plus user input within 5s means a human raised it, so it returns user-foreground instead of bottoming even under force; a PDF self-pop with idle hands still gets demoted. All re-assert and park callers stop retrying on that signal and mark the session userActive so every later demotion timer skips it for 10 minutes
John Lauer
·
b2701b1
·
1d ago
One visible taskbar mutation per window open instead of three, from John watching the button live: the create-time identity stamp fired before session registration so its result was never recorded and the post-park re-brand recreated the button again with the identical appId (pre-registration stamps are now remembered and adopted at registration so the second stamp truly no-ops), and the favicon overlay no longer races onto the still-Chrome button just to be wiped by the stamp (young windows defer overlay until identity lands, stamp-once then overlay-once, with a 30s grace so an unstampable window is never left bare)
John Lauer
·
de16b23
·
1d ago
Apply John's own Generate of the aligned hero (identical composition, his provenance stamp)
John Lauer
·
d21b819
·
1d ago
Title mangling fully dead, completing what John asked when the jump-list owner task shipped: the three legacy always-on title-suffix injectors (launch path, adopted-tab retag, post-navigate) predated the titleTag setting and kept appending the ai-thread/profile suffix with their own observers; they now stamp only the invisible window.name carrier and strip legacy tags, installing nothing and observing nothing. Ownership is conveyed solely by the jump-list Owned-by task and the pup_window_info native card
John Lauer
·
467ee18
·
1d ago
Apply the alignment-fixed hero: logo, Pup title, and subtitle ink edges flush at x=80 (kicad-thread catch: the title sat 18px right of the logo), generated via hero-studio on John's go
John Lauer
·
d3b48e2
·
1d ago
Hero build: ink-precise left alignment via empirical measured offsets for logo, title, and subtitle (PIL textbbox under-reports Familjen's left bearing at 240px, which put the Pup title 18px right of the logo, caught by the kicad thread)
John Lauer
·
67fab5a
·
1d ago
Zero synchronous PowerShell: all 7 remaining execFileSync window-management helpers (idle probe, foreground reads, force-activate, the three backgrounding paths, z-bottom, flash-clear) are now async with every call site awaited, so pup's event loop can never again stall on a powershell spawn and starve ab's health probe (the ab61 reap trigger); the sync runner carries a do-not-add-callers tombstone until ab ships native window verbs and PowerShell is deleted outright
John Lauer
·
8d146e1
·
1d ago
Caption card copy polish: replace em-dashes with middots in the pup_window_info native card per the house style for user-facing copy
John Lauer
·
8428d1c
·
1d ago
Ownership conveyed the way John designed it instead of title mangling: every pup window's jump-list now leads with an 'Owned by: <ai-thread>' task, and clicking it runs the new pup_window_info verb, which paints a native always-on-top click-through caption card just above the taskbar (ab desktop_caption, 12s auto-dismiss) showing the owning thread, container, profile, tabs, window age, last agent action, and any takeover history; the verb also returns the same info as JSON for AI callers and is read-only and never owner-gated
John Lauer
·
ddfbe77
·
1d ago
Hotfix for the frozen-window regression John hit within the hour: revert the titleTag default to off (the v2.0.19 flip re-armed the documented title-observer ping-pong that pegs renderers and froze hd-publish-1.0.0), harden the opt-in observer to only ever watch a real title node instead of the whole document subtree on titleless pages, and make takeover:true on one-shot verbs act without stealing ownership so a sanctioned repair reload does not lock the original thread out of its own window
John Lauer
·
05ef140
·
1d ago
Hard window ownership keyed on caller identity: every window-mutating verb naming an explicit sessionId is refused with session_owned_by_another_thread when that session belongs to a different AI thread (the old gate compared only the optional args.owner field and covered just navigate and close, so undeclared callers could take over other threads' windows, the kicad-vs-nb incident John caught); takeover:true is logged with both thread names and reassigns ownership. Ownership is now user-visible too: the ai-thread title tag defaults on so taskbar hover and Alt-Tab name the owner, and the jump-list header carries the owning thread
John Lauer
·
9dd76c4
·
1d ago
Update page: pup-bridge
John Lauer
·
7fd5164
·
1d ago
Update page: pup-bridge
John Lauer
·
33827fe
·
1d ago
Publish 2.0.18
John Lauer
·
c685e33
·
1d ago
Keep page.json tags in lockstep with the live page: add the ab tag (pup is an ab bridge)
John Lauer
·
9bae5c5
·
1d ago
Add the ab tag: pup is an ab (Adom Bridge) bridge, so the ab shorthand belongs in its tag set alongside bridge and pup
John Lauer
·
fa160ae
·
1d ago
pup-hero-image skill: record that the human gate is John's approval (the AI may click Generate with his explicit go-ahead), and that the studio re-renders imports on Generate so exports must be verified visually, not by pixel probes
John Lauer
·
6d6c088
·
1d ago