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.
← Commit history
doctrine: reconcile placement with v2.0.276 off-screen-birth + <50ms park (measured 27ms, 0/95 foreground steal); delete focus-handback; off-screen banned only as resting/staging/fallback, sanctioned as a guaranteed sub-50ms birth transient
2 files changed
+99−37
dev-skills/pup-bridge-dev/SKILL.md+75−25@@ -344,10 +344,26 @@ R1 never visually pop / cover the user's work · R2 the window is reachable (tas were set after a pup window opened off-screen behind a live taskbar button for the second time in one day: *"you need to allow a user to open a pup window immediately if they want to."* -**R1 BIRTH IT ON SCREEN, IN ONE CALL.** `Target.createTarget` accepts `left/top/width/height`, so the-window is CREATED at its final geometry: the PRIMARY MONITOR's work area inset **10px on all four-sides**. There is no staging position, no migration, no "place it once we are sure". The window is-reachable from its first millisecond because it was never anywhere else.+**R1 BIRTH IT OFF-SCREEN, PARK IT ON-SCREEN WITHIN 50ms — UNCONDITIONALLY (revised 2026-08-22, v2.0.276).**+`Target.createTarget` is created at `-32000,-32000`, then IMMEDIATELY moved by `Browser.setWindowBounds`+to its final geometry (the PRIMARY MONITOR's work area inset **10px on all four sides**) in the same+synchronous stretch of `createPageInNewWindow`. Measured move time: **27ms** (budget 50ms). The window+reaches its final, clickable rect within one animation frame; off-screen is a sub-50ms BIRTH TRANSIENT,+never a resting state, never a staging state that waits for a proof, never an uncertainty fallback.++This REVERSES the 2026-08-20 "birth on-screen in one call" rule, and here is the honest why. On-screen+birth made the window clickable from millisecond zero (good) but it also let **Chrome self-activate the+visible window and steal the foreground** — the whole reason the old rule needed a focus-handback and the+R6 birth-grace bolted on beside it. On 2026-08-22 that machinery failed in the field: the handback+foregrounded the WRONG window (usually another pup window, with no caption), and the "Windows foreground+lock protects an actively-used machine" claim did not hold when John was WATCHING pup work, not typing.+Off-screen birth is the ONE reliable lever that stops the steal at its source — **Chrome does not bother+activating a window that is nowhere** (the old doctrine measured this itself: "the off-screen birth was+doing half the work"). John's directive: *"off-screen birth could work as LONG AS YOU MOVE IT TO THE MAIN+SCREEN WITHIN 50ms."* The <50ms unconditional move is what keeps R3 (a taskbar click always works) whole:+the window is never left off-screen, so it can never strand — the 2.0.258-and-earlier failure this skill+was built to kill came from off-screen as a RESTING/STAGING/FALLBACK state gated on a self-defeating+`zConfirmedBelow` proof, NOT from a guaranteed-transient birth. Do not conflate the two. **R2 BACKGROUND IS THE PREFERENCE, NOT A PRECONDITION.** `--no-startup-window` is what actually keeps the foreground (the browser process holds no foreground rights by the time CDP creates the window), and@@ -358,9 +374,15 @@ re-park loop, and every one of those eventually yanked a real click. **R3 A TASKBAR CLICK MUST WORK, ALWAYS, WITH NO HELP FROM PUP.** The moment the user clicks the button, the window comes to the foreground and they see it. This is a REQUIREMENT, not a trade. Any state that-breaks it — off-screen, hidden, cloaked, `WS_EX_NOACTIVATE` — is forbidden as a resting state and as a-transient one. There is no "launch-gap contract" any more; the old text promised ~2s and the shipped-code could hold a window unreachable for **42 seconds** (8 bottom attempts x a 5s ab timeout + sleeps).+breaks it — off-screen, hidden, cloaked, `WS_EX_NOACTIVATE` — is forbidden as a **resting state, a+staging state, and an uncertainty fallback.** The ONE sanctioned exception is R1's off-screen BIRTH+transient: off-screen for the sub-50ms it takes the unconditional on-screen move to run, because that move+is immediate and never gated on a proof, so the window is at its final clickable rect within one animation+frame and can never strand there. The distinction is the whole game: a guaranteed-transient birth is safe;+off-screen held open "until we are sure it is safe to show" is the exact self-defeating state that broke+this before (see the struck `zConfirmedBelow`). There is no "launch-gap contract"; the old text promised+~2s and a shipped code path could hold a window unreachable for **42 seconds** (8 bottom attempts x a 5s+ab timeout + sleeps). `sweepVisibility` (30s) backstops any birth move that somehow fails to land. **R4 IDENTITY IS CAPTURED AT BIRTH, EXACTLY, AND NEVER LOST.** The hwnd is resolved in the same locked moment the window is created and stashed on the page. See `pup-window-targeting`; the mechanism is a@@ -433,9 +455,9 @@ Chrome's self-activation of an *unasked-for* window being read as intent. |---|---|---| | `primaryWorkArea()` | `server.js` | `SystemParametersInfo(SPI_GETWORKAREA)` via one PS call, cached 5 min. Answers WITHOUT a window, which is the chicken-and-egg that pushed the old design into staging off-screen (`screen.availWidth` needs a page that does not exist yet). | | `birthRect()` | `server.js` | Work area inset 10px on all four sides. Falls back to `10,10 1280x800` — conservative, never off-screen. |-| `createPageInNewWindow` | `server.js` | `Target.createTarget {newWindow:true, left, top, width, height}` — the window is CREATED at its final rect. |+| `createPageInNewWindow` | `server.js` | `Target.createTarget {newWindow:true, left:-32000, top:-32000, width, height}` then an IMMEDIATE `Browser.getWindowForTarget` + `Browser.setWindowBounds` to the on-screen `birthRect()`. Off-screen birth (Chrome never activates a nowhere window) + unconditional sub-50ms move (measured 27ms). Logs `[birth] window moved off-screen -> on-screen (x,y) in Nms (budget 50ms)`. | | birth hwnd capture | same fn | `withBirthLock` + top-level window set-diff filtered to THIS profile's Chrome PIDs. No coordinate involved. If >1 window appears under the lock it **refuses to guess** and logs loudly — a wrong hwnd paints another window's badge and parks the wrong window, so late beats wrong. |-| focus handback | same fn | If `createTarget` took the foreground, hand it straight back once. Window is never moved. |+| ~~focus handback~~ DELETED (v2.0.276) | same fn | The 2026-08-20 handback (`createTarget took the foreground → hand it back once`) is GONE. It existed only to undo the steal that on-screen birth caused; off-screen birth removes the steal at its source, so there is nothing to hand back. In its place a pure DIAGNOSTIC logs `[focus] UNEXPECTED: a new window took the foreground despite off-screen birth` — if it ever fires, investigate, do NOT re-add a handback (the handback was itself the thing that foregrounded the wrong pup window on 2026-08-22). | | `parkSessionWindowDirect` | `server.js` | No longer a placement gate. 3 bounded bottom attempts, then `placeOnScreen()` unconditionally. Cannot move/hide/off-screen a window when it fails. | | `BIRTH_GRACE_MS` / `inBirthGrace()` | `server.js` | R6, above. | | `sweepVisibility` | `server.js` | 30s BACKSTOP only. Repairs hidden and off-screen windows population-wide by owning PID. Leaves minimized alone. |@@ -446,9 +468,29 @@ returned false whenever our hwnd was absent from ab's enumeration — which an o is, so the failure sustained itself, and it has no correct answer at all when the user has no other windows open). -## VERIFIED — the run that closed this out (2026-08-20, pup 2.0.259-261)+## VERIFIED — off-screen birth restored (2026-08-22, pup 2.0.276) -Measured, not asserted. Re-run these before believing any future change to the open path.+The 2026-08-20 on-screen-birth approach below regressed in the field (Chrome self-activated newborn+windows; the handback then foregrounded the wrong pup window). Off-screen birth + <50ms park was+re-shipped and MEASURED:++| Claim | How it was measured | Result |+|---|---|---|+| No foreground steal | Sampled `GetForegroundWindow` every 80ms for 9s spanning a full background open | **0 of 95 samples held by a pup window; foreground never left John's Edge window** |+| Move is within budget | `[birth] window moved off-screen -> on-screen` log line | **27ms** (budget 50ms) |+| Window lands on-screen, clickable | Probed the birthed window's rect via `GetWindowRect` after the open | **`10,10 1687x999` — on-screen, not stranded** |+| Nothing stranded off-screen | `sweepVisibility` backstop unchanged (30s) | still repairs any off-screen/hidden window population-wide |++The two failure modes this reconciles: **stranded off-screen** (pre-2.0.259 — off-screen as a+resting/staging/fallback state gated on a self-defeating proof) is prevented because the move is+unconditional and immediate; **foreground steal** (2.0.259-275 — on-screen birth self-activated by+Chrome) is prevented because Chrome never activates a nowhere window. Both are now closed at once.++## VERIFIED — the run that closed this out (2026-08-20, pup 2.0.259-261) — SUPERSEDED on the birth position by 2026-08-22 above++Measured, not asserted. Re-run these before believing any future change to the open path. NOTE: the+"Born on-screen, never staged" row below was REVERSED 2026-08-22 (birth is off-screen again, then+parked on-screen in <50ms); the hwnd-exactness and R6 rows still stand. | Claim | How it was measured | Result | |---|---|---|@@ -497,16 +539,20 @@ hwnd against `GetWindowText`; open one while typing and assert the log says `bot **Still true, still load-bearing (do not re-derive):** - `--no-startup-window` is load-bearing, but **it was never the whole focus fix** — MEASURED on- ConfRoomROG the moment R1 landed (2026-08-20). The off-screen birth was doing half the work,- because Chrome does not bother activating a window that is nowhere. Born at a real rect, Chrome- activates it, and every open logged `[focus] createTarget took the foreground`. The old playbook- asserted this could "never show a steal" and told you to investigate if it ever did; here is that- investigation. Keep the flag (it still stops the LAUNCH-time grab), and keep the handback below.-- **The focus handback is required, and it is NOT a re-park loop.** R2 says accept a foreground- WINDOW; the user's KEYBOARD focus is a separate thing, and letting their typing land in a browser- that just appeared is not a flaw worth accepting when handing focus back costs one call. One shot,- at birth (the restored v1.9.253 handback), never on a timer, and it reports when it fails. The- window itself is never moved as a result — that distinction is the whole reason this is allowed.+ ConfRoomROG the moment R1 (on-screen birth) landed (2026-08-20). The off-screen birth was doing+ half the work, because Chrome does not bother activating a window that is nowhere. Born at a real+ on-screen rect, Chrome activates it, and every open logged `[focus] createTarget took the foreground`.+ **2026-08-22 update:** that "born at a real rect → steal" is exactly what recurred in the field, so+ R1 now BIRTHS OFF-SCREEN again (then parks on-screen in <50ms) — restoring the half of the fix that+ was doing the work. Keep the flag (it still stops the LAUNCH-time grab); the off-screen birth handles+ the rest, so the handback below is GONE.+- **The focus handback was DELETED (v2.0.276) — do not bring it back.** It was born on 2026-08-20 to+ undo the steal that on-screen birth caused. With off-screen birth there is no steal to undo, and the+ handback had a fatal flaw of its own: the "previous foreground" it handed focus back to was usually+ ANOTHER pup window, so it FOREGROUNDED unasked-for pup windows with no caption — the 2026-08-22+ regression John hit. The correct fix is to stop the steal at the source (off-screen birth), not to+ chase it after the fact. A pure diagnostic (`[focus] UNEXPECTED ...`) replaces it; if it ever fires,+ investigate the birth path, never re-add a handback. - Geometry via **CDP bounds only**, addressed by windowId. NEVER `windowState:'maximized'`, NEVER ab `desktop_set_window_bounds` — both RAISE the window. - **Nothing re-parks a window the user has raised.** `userIsUsingWindow()` gates every demotion.@@ -517,10 +563,14 @@ hwnd against `GetWindowText`; open one while typing and assert the log says `bot **Supporting principles (subordinate to THE RULES above — where older text conflicts, the rules win):** -1. **~~Launch OFF-SCREEN~~ — STRUCK 2026-08-20.** This was the root of every "I clicked the taskbar- button and nothing came up" report. Windows are born at their FINAL on-screen rect (R1). The- `--window-position=-32000,-32000` launch arg is also gone (removed in v1.9.135 for a separate- reason: it poisoned the restore rect of every Chrome-created window, including popups).+1. **Launch off-screen as a RESTING/STAGING state — STRUCK 2026-08-20, and still struck.** Holding a+ window off-screen "until we prove it is safe to show" was the root of every "I clicked the taskbar+ button and nothing came up" report, and that ban stands. What was REINSTATED 2026-08-22 (v2.0.276)+ is off-screen BIRTH as a guaranteed sub-50ms transient (R1) — a different thing: the window is moved+ on-screen unconditionally within one frame, never held there pending a proof. The+ `--window-position=-32000,-32000` launch ARG stays gone (removed v1.9.135 for a separate reason: it+ poisoned the restore rect of every Chrome-created window, popups included); the off-screen birth is+ done via `Target.createTarget` coordinates + an immediate `setWindowBounds`, not that launch arg. 2. **The resting state is ON-SCREEN at the bottom of the z-order** → and now the BIRTH state too. On-screen-occluded (behind the user's windows, taskbar-clickable, still compositing) is the ONLY state that satisfies R3 while keeping screenshots working — see the minimize dead-end.
dev-skills/pup-user-foreground/SKILL.md+24−12@@ -32,17 +32,25 @@ loaded gun pointed at the user's click. ## The doctrine (current, settled) -1. **Background means BEHIND, never hidden — and now, never ANYWHERE ELSE FIRST.** As of- 2026-08-20 this is no longer just the resting state, it is the BIRTH state: a window is created- at its final on-screen rect (primary work area, 10px inset) in the `Target.createTarget` call- itself, at z-bottom, never off-screen and never minimized. A taskbar click reveals it with no- help from pup, from the first millisecond of its life.- You were right in v1.9.133/134 (after the "click the flash, see nothing" bug) and this rule was- correct the whole time; what it lacked was force over the older `pup-bridge-dev` playbook, which- said the opposite ("leave the window invisible off-screen") and which the CODE was following.- **THE PLACEMENT RULES NOW LIVE IN ONE PLACE: `pup-bridge-dev` → THE RULES (R1-R5).** This file- governs the user-vs-pup FIGHT (who may raise, who may demote); it defers to those for geometry.- If you find any text anywhere that permits an off-screen window, it is stale — delete it.+1. **Background means BEHIND, never STRANDED — and the RESTING state is always on-screen at z-bottom.**+ The invariant that matters: no pup window may ever be left in a state the user cannot click to+ (hidden, minimized-by-pup, or held off-screen). The RESTING state is on-screen, at z-bottom, primary+ work area inset 10px — a taskbar click reveals it with no help from pup.+ **On the BIRTH position, this rule was wrong from 2026-08-20 to 2026-08-22 and is now corrected.**+ That window it said "born on-screen in one call, never off-screen" — but on-screen birth lets Chrome+ self-activate the newborn and steal the foreground (the 2026-08-22 regression: unasked-for pup+ windows fronting John's screen with no caption). As of v2.0.276 a window is BORN OFF-SCREEN+ (`-32000,-32000`, so Chrome never activates it) and moved to its final on-screen rect UNCONDITIONALLY+ within 50ms (measured 27ms). Off-screen is a guaranteed sub-50ms BIRTH TRANSIENT — never a resting+ state, never a staging state that waits for a proof, never an uncertainty fallback. Those three ARE+ still banned (they are what strand a window; see rule 7). The v1.9.133/134 insight still holds: a+ window the user cannot reach is the cardinal sin. What changed is that the fix for Chrome's+ self-activation is off-screen BIRTH, not on-screen birth + a focus handback (that handback was+ deleted; it foregrounded the wrong window).+ **THE PLACEMENT RULES LIVE IN ONE PLACE: `pup-bridge-dev` → THE RULES (R1-R6).** This file governs+ the user-vs-pup FIGHT (who may raise, who may demote); it defers to those for geometry. If you find+ text anywhere that permits a RESTING or STAGING off-screen window, it is stale — delete it; but do+ not delete the sanctioned sub-50ms birth transient. 2. **User intent is read from the OS, atomically, inside the demotion primitive.** `GetForegroundWindow() == our hwnd` AND `GetLastInputInfo` idle < 5s means a HUMAN raised it (a keyboard/mouse was active). A programmatic self-raise happens with idle hands. This check@@ -125,7 +133,11 @@ loaded gun pointed at the user's click. ## Bans (each one shipped and hurt) - No demotion path outside the shared primitive / without the `userIsUsingWindow` check.-- No off-screen or minimize-based backgrounding of a window the user can see on the taskbar.+- No off-screen or minimize-based BACKGROUNDING of a window the user can see on the taskbar. (The+ off-screen BIRTH transient — `-32000,-32000` for the sub-50ms before the unconditional on-screen park,+ v2.0.276 — is the one sanctioned exception, because it is never a resting/staging/fallback state; see+ rule 1 and `pup-bridge-dev` R1/R3. Off-screen held open for any reason other than that one immediate+ move is the banned thing.) - No re-park retry LOOPS (the playbook ban): one pass + the scheduled re-asserts, then stop. - No trusting session flags alone for "is the user using this" at demotion time - flags lag; the OS check rides in the demotion pass itself.