Conversation
Add design document for a configurable browser event streaming system that captures CDP events (console, network, DOM, layout shifts, screenshots, interactions), tags them with tab/frame context, and writes them durably to S2 streams. Co-authored-by: Cursor <cursoragent@cursor.com>
- layout_settled: start 1s timer after page_load, reset on each shift, emit when timer expires. Handles zero-shift pages correctly. - screenshots: downscale PNG by halving dimensions if base64 exceeds ~950KB, rather than truncating (which corrupts binary data). Co-authored-by: Cursor <cursoragent@cursor.com>
| | Type | Trigger | | ||
| |------|---------| | ||
| | `network_idle` | Pending request count at 0 for 500ms after navigation | | ||
| | `layout_settled` | 1s of no layout-shift entries after page_load (timer resets on each shift) | |
There was a problem hiding this comment.
Good catch -- the table and description were contradictory. Fixed in 7b9c491: after page_load, start a 1s timer. Each layout shift resets the timer. layout_settled fires when the timer expires (1s of quiet). For zero-shift pages, this correctly fires 1s after page_load.
| | `interaction_key` | Injected JS | key, selector, tag | | ||
| | `interaction_scroll` | Injected JS | from_x, from_y, to_x, to_y, target_selector | | ||
| | `layout_shift` | Injected PerformanceObserver | score, sources (element, previous_rect, current_rect) | | ||
| | `screenshot` | ffmpeg x11grab (full display) | base64 PNG in data | |
There was a problem hiding this comment.
Valid concern -- truncating base64 PNG data produces corrupt output. We don't support 4K displays so this is unlikely in practice, but the plan now specifies: if the base64 PNG exceeds ~950KB, downscale by halving dimensions and re-encode. This keeps a usable PNG under the 1MB S2 limit. Fixed in 7b9c491.
ulziibay-kernel
left a comment
There was a problem hiding this comment.
is this an infra through we we can log IP addresses the browser sessions are assigned to? That is highly relevant for https://linear.app/onkernel/issue/KERNEL-801/residential-ip-reputation-measurement
Sayan-
left a comment
There was a problem hiding this comment.
building on top of CDP, S2 makes sense! I think the main risks are going to be some of the signal settling + chromium lifecycle handling but all solvable problems
|
Responding to all of @Sayan-'s comments inline below. Will push a spec update commit shortly. CDP perf (L37): Dug into the Chromium source ( monitor_disconnected/reconnected (L39): Agreed. Will add Sequence ID / ordering (L52): Will add a monotonic cdp_session_id (L56): Good call. Renaming Custom transform semantics (L67): Confirmed — this is intentional. Each event type has a custom handler that maps CDP params into our Ring buffer as single write path (L204): Yes — rewiring the architecture so the monitor writes only to the ring buffer, and the S2 writer is just another consumer (like SSE clients). Single write path, S2 latency decoupled from CDP processing. Updating the diagram and description. Testing gaps (L235): Adding failure mode test scenarios: Chrome crash/restart during capture (verify |
…tecture, failure tests - Add monotonic `seq` field to BrowserEvent for total ordering and SSE reconnection - Rename session_id → cdp_session_id to avoid confusion with Kernel sessions - Rewire architecture: monitor writes only to ring buffer, S2 writer is a consumer - Add CDP connection isolation note (confirmed from Chromium source) - Add monitor_disconnected/reconnected synthetic events for gap detection - Add e2e_events_failure_test.go for Chrome crash, ring buffer overflow, early start - Update SSE endpoint to include id: <seq> for Last-Event-ID support Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot Autofix prepared fixes for 3 of the 3 bugs found in the latest run.
Or push these changes by commenting: Preview (80a186b49e)diff --git a/.cursor/plans/2026-02-05-events.md b/.cursor/plans/2026-02-05-events.md
--- a/.cursor/plans/2026-02-05-events.md
+++ b/.cursor/plans/2026-02-05-events.md
@@ -54,20 +54,21 @@
```go
type BrowserEvent struct {
- Seq uint64 `json:"seq"` // monotonic sequence number, resets on server startup
- Timestamp int64 `json:"ts"` // unix millis
- Type string `json:"type"` // snake_case event name
- TargetID string `json:"target_id,omitempty"` // CDP target ID (tab/window)
- CDPSessionID string `json:"cdp_session_id,omitempty"` // CDP session ID (not Kernel session)
- FrameID string `json:"frame_id,omitempty"` // CDP frame ID
- ParentFrameID string `json:"parent_frame_id,omitempty"` // non-empty = iframe
- URL string `json:"url,omitempty"` // URL context
- Data json.RawMessage `json:"data"` // event-specific payload
- Truncated bool `json:"truncated,omitempty"` // true if payload was cut to fit 1MB
+ CaptureSessionID string `json:"capture_session_id"` // unique ID generated at each capture start (UUIDv4), stable across reconnects within one session
+ Seq uint64 `json:"seq"` // monotonic sequence number, resets on server startup
+ Timestamp int64 `json:"ts"` // unix millis
+ Type string `json:"type"` // snake_case event name
+ TargetID string `json:"target_id,omitempty"` // CDP target ID (tab/window)
+ CDPSessionID string `json:"cdp_session_id,omitempty"` // CDP session ID (not Kernel session)
+ FrameID string `json:"frame_id,omitempty"` // CDP frame ID
+ ParentFrameID string `json:"parent_frame_id,omitempty"` // non-empty = iframe
+ URL string `json:"url,omitempty"` // URL context
+ Data json.RawMessage `json:"data"` // event-specific payload
+ Truncated bool `json:"truncated,omitempty"` // true if payload was cut to fit 1MB
}-The Event Types@@ -101,6 +102,12 @@ These events let consumers detect gaps in the event stream rather than silently missing events during Chrome restarts. +On reconnect, the monitor must perform a full state reset before re-subscribing to CDP domains: | Type | Trigger |
|
- Add capture_session_id (UUIDv4) to BrowserEvent schema for robust deduplication via (capture_session_id, seq) instead of (seq, type, ts), preventing silent data loss across server restarts. - Document computed_events config dependencies (network, navigation, layout_shifts, interactions) and specify auto-enable with warning. Without these, computed events produce vacuously-true or never-firing signals. - Specify full settling state reset and script re-injection on Chrome crash reconnection: zero request counter, cancel timers, clear boolean flags, re-inject PerformanceObserver and interaction tracking JS. Update test plan to verify post-reconnect behavior. Applied via @cursor push command
|
Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.
Or push these changes by commenting: Preview (84e8f5d0c7)diff --git a/.cursor/plans/2026-02-05-events.md b/.cursor/plans/2026-02-05-events.md
--- a/.cursor/plans/2026-02-05-events.md
+++ b/.cursor/plans/2026-02-05-events.md
@@ -201,7 +201,7 @@
type: array
items:
type: string
- enum: [error, page_load, navigation_settled, scroll_settled, network_idle]
+ enum: [error, page_load, navigation_settled, scroll_settled, network_idle, layout_settled]
description: Which events trigger a screenshot. Default [error, navigation_settled]
targets:
type: boolean |
The screenshot_triggers enum included all computed events (network_idle, scroll_settled, navigation_settled) except layout_settled. This was an oversight since layout_settled is a distinct computed meta-event and should be available as a screenshot trigger for capturing visual stability moments independently of network activity. Applied via @cursor push command

Summary
Design document for a configurable browser event streaming system on the image server.
Target.setAutoAttachwithflatten: truenetwork_idle,layout_settled,navigation_settled(composite of dom_content_loaded + network_idle + layout_settled)POST /events/startwith a config bodytruncatedflagThe full RFC is in
.cursor/plans/2026-02-05-events.md. Also addsdevtools-protocol/as a reference for CDP domain definitions.Test plan
Made with Cursor
Note
Low Risk
Documentation-only change that adds no runtime code or API surface; low risk aside from potentially setting expectations for future implementation.
Overview
Adds a new RFC document (
.cursor/plans/2026-02-05-events.md) describing a proposed browser event capture/streaming system for the image server.The doc specifies the intended event schema, capture configuration and endpoints (
/events/start,/events/stop,/events/stream), computed “settling” events, multi-target CDP strategy, screenshot/S2 streaming approach, and a planned testing matrix.Written by Cursor Bugbot for commit 30372ae. This will update automatically on new commits. Configure here.