Repository navigation
Screen stream (WebRTC): telepointers, the iPhone draws the person's and the agent's pointers (Petal) - #36086
Screen stream (WebRTC): telepointers, the iPhone draws the person's and the agent's pointers (Petal)#36086teamleaderleo wants to merge 4 commits into
Conversation
Petal's telepointers (telepointer.rs, Apache-2.0): a viewer that draws pointers says so in a caps message; the host then leaves the cursor out of the picture (SCStreamConfiguration.showsCursor) and sends the person's pointer and the agent's, as fractions of the streamed display, on the unordered pointer channel at up to 60 Hz when they move (and once a second). The iPhone viewer draws the person's as the cursor and the agent's as a ring. Older viewers, and the Mac viewer, keep the cursor in the picture. Two app hooks, nil by default: ScreenStreamHost.agentPointer (global display points) and ScreenCaptureBackend.excludedProcessIDs (the agent cursor overlay's helper, left out of the capture). Asked for by cu-codrive (HQ#7146 co-driving). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-29da0cfaa02255d6b3d5
|
@azooz2003-bit, for your awareness. These are Petal ports on the WebRTC stream path (HQ#7146), all in
Old viewers and the Mac viewer keep today's behaviour in each. None of them changes the cmux.rd/1 path. If one of them steps on something you have in flight, say so and I'll rebase around it. |
|
Review (codex gpt-6-astra high, router-review): BLOCK at c3eb9c1 BLOCK at c3eb9c1 Visual verdict: no images; Leo tries the build
Follow-ups:
|
…iPhone keeps pointers as fractions Codex review at c3eb9c1: setDrawsCursor(false) arriving while startCapture() awaited left the cursor in the picture (only the rate was checked after), and a pointer that came before the first video frame stayed at (0, 0). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-29da0cfaa02255d6b3d5
|
Replies to the router review at c3eb9c1. Fixed in e2d4fc7:
|
…ks under the lock; clear pointers on a new stream Codex review at e2d4fc7: the helper's windows were left out for a viewer that draws no pointers; the telepointer task was appended to session.tasks without the lock while endSession could cancel them (every session task now goes through Session.add, which cancels one started after the end); and the iPhone kept the last host's pointers across a reconnect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-29da0cfaa02255d6b3d5
|
Review (codex gpt-6-astra high, router-review): BLOCK at e2d4fc7 BLOCK at e2d4fc7 Visual verdict: no images; Leo tries the build
Follow-ups:
|
|
Review (codex, router-review): SHIP at 2d70492 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 2. They land as checklist items in this PR's one follow-up tracking issue in this repo ( SHIP at 2d70492 Visual verdict: no images; Leo tries the build
Follow-ups:
|
Codex follow-up at 2d70492: capture() recorded the pids as applied when SCShareableContent failed and the filter fell back to the whole display, so the 2 s watcher never retried. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-29da0cfaa02255d6b3d5
teamleaderleo
left a comment
There was a problem hiding this comment.
Review (claude-opus-5-5): SHIP at 86a657d
Delta on top of Codex's SHIP at 2d70492 (read directly; one file): fixes Codex follow-up F2. filter() now says whether the pids were left out; capture() records excludedApplied only when they were, and the 2 s watcher skips updateContentFilter when the window list failed, so a transient SCShareableContent failure is retried instead of leaving the helper's windows captured. Compile check CmuxVNCWebRTC passed at this head (job 3cdbab5186ff88582a87e6f9). F1 (wiring agentPointer/excludedProcessIDs in MacScreenRdHost.serveWebRTC) is cu-codrive's app-side follow-up, sent to them with the exact site.
Leo, 2026-11-05: "honestly i'd rather us look at lot more at Petal and stuff like we ought to be able to get a lot more efficient and start going towards crazy stuff... after being able to do the basics end to end and adding eval measurements, ofc", and on the Petal list: "obv do all these and more".
HQ#7146 G5 (a person and an agent co-driving), asked for by the cu-codrive lane. Ports Petal's telepointers: cursors as metadata, never pixels (https://github.com/kiruna-labs/petal @ 7ac436a, Apache-2.0,
src/telepointer.rs).What changes
Today the WebRTC display stream draws the Mac's cursor into the video (
showsCursor = true) and captures the Computer Use agent's cursor overlay window along with everything else.capsinput withtelepointers. An older host ignores it.showsCursorturns off, applied withupdateConfigurationwithout restarting the capture. The host then sends{t:"telepointers", person:{x,y}, agent:{x,y}}, each a 0–1 fraction of the streamed display and absent when off it. Messages go out on the unorderedpointerchannel (latest wins), sampled at 60 Hz, sent only when a pointer moved, plus once a second. Older viewers and the Mac viewer never send the capability, so they keep the cursor in the picture.ScreenViewController). The person's pointer is the existing arrow, at the Mac's pointer position in direct mode; trackpad mode and a hovering iPad pointer keep their local cursor. The agent's pointer is a ring with a tinted centre. Both keep a readable size when zoomed out.ScreenStreamHost.agentPointer: (@Sendable () -> CGPoint?)?: the agent's pointer in global display points (top-left origin, asCGEventlocations). The host converts it to the streamed display's fraction. Feed it fromComputerUseAgentCursorWindows.fraction(_:in:)'s tips (the overlay window centres).ScreenCaptureBackend.excludedProcessIDs: (@Sendable () -> [pid_t])?: processes whose windows stay out of the capture (the Computer Use helper that owns the overlay windows). It is read at each capture start and every 2 s, and applied withupdateContentFilter. It excludes by process, not window ID, so overlay windows created after the capture started stay out too.This also helps the skip gate (#36065) and the bitrate: a pointer move no longer changes the picture, so it costs no encoded frame.
Numbers
Pending, from screen-stream-g0's harness (cmux#36043, not yet on feat-cmux-next). Its viewer doesn't send
telepointers, so its rows show the default path unchanged. The expected wins are kbps while only the pointer moves, and pointer glass-to-glass: the marker is drawn from metadata, not decoded video. Measuring them needs a harness viewer that advertises the capability; I'll ask screen-stream-g0. Draft until then.Tests
TelepointerTests(new): the capability check, display fractions on a second display, the message's encoding and old-viewer compatibility.Observed / Not run
CmuxScreenKitUI(no iOS compile route from this lane VM; CI's iOS simulator build covers it), a device session, the macOS package tests (CI).Changelog
🤖 Generated with Claude Code
Agent session: agent session