Skip to content

feat(macos): draw a ghost cursor for native app backend actions - #3195

Merged
thymikee merged 1 commit into
feat/macos-native-app-backendfrom
feat/macos-ghost-cursor
Oct 4, 2026
Merged

thymikee merged 1 commit into
feat/macos-native-app-backendfrom
feat/macos-ghost-cursor

Conversation

@thymikee

@thymikee thymikee commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Summary

Draws a ghost cursor for native-backend actions (#3189), so a person can follow the agent while keeping the real pointer. Each helper action shows a pointer just above-left of the target, glides onto it, and pulses on delivery.

  • About 0.3 s per action; no linger after delivery.
  • No state between helper processes: no temp file, nothing shared across sessions.
  • AGENT_DEVICE_MACOS_GHOST_CURSOR=0 turns it off; the 1 s helper-deadline budget applies only when the cursor is drawn. Documented in configuration.md.

Split from #3188 to keep each layer within the diff budget. 9 files.

Validation

  • pnpm check:affected --run passed on a2a54730a; swift test passed. Tests pin the env, cover the 0 opt-out argv, and the conditional deadline budget.
  • Live: the cursor glided and pulsed over background Calculator, TextEdit, Codex and T3 Code while the real pointer stayed put; window screenshots exclude it.

🤖 Generated with Claude Code

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 9 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/platform-apple/src/os/macos/native-app-interactor.test.ts
Comment thread apple/macos-helper/Sources/AgentDeviceMacOSHelper/GhostCursor.swift Outdated
Comment thread packages/platform-apple/src/os/macos/helper.ts Outdated
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.01 MB 5.01 MB +6.2 kB
Package (unpacked) 5.01 MB 5.01 MB +6.2 kB
Package (download) 1.50 MB 1.50 MB +2.1 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 18.7 ms 18.7 ms -0.0 ms
CLI --help 57.2 ms 55.5 ms -1.7 ms

@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://callstack.github.io/agent-device/pr-preview/pr-3195/

Built to branch gh-pages at 2026-10-04 08:27 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@thymikee

thymikee commented Oct 3, 2026

Copy link
Copy Markdown
Member Author

I found no blocking problems at 4e617c8, and all 21 checks pass. No CI job runs the helper's AppKit drawing path, so green CI says nothing about the panel itself. No conflicts, and nothing blocks merge. I did not run the helper live, so the glide, pulse, screenshot exclusion and unmoved pointer rest on code reading and your description. I also could not check how NSApplication.shared behaves without a WindowServer connection (ssh or headless host). Code reading suggests it only logs.

Not blocking, and you can take or leave these. The cursor is on by default, and the helper animates before and after delivery: show() and move() run before perform, and pulse() and the linger run before the reply. By my reading of the hard-coded durations, each native press, fill or scroll returns about 0.65 s later, plus the first WindowServer connection. I did not measure it. A SIGTERM during the linger also reports a delivered action as failed. Dropping the post-delivery linger, or making the cursor opt-in, would fix most of this. Either way, please note the per-action latency in configuration.md. Also, no test sends AGENT_DEVICE_MACOS_GHOST_CURSOR=0 through runMacOs*Action, so the opt-out at helper.ts:123 is not asserted. One case that sets it to '0' and checks that argv has no --ghost-cursor would cover it.

Could a smaller version work? The change adds a public env surface across the Swift helper, the TS host and docs. Dropping cross-process persistence (positionURL, restoredPosition, persist, about 25 lines) would remove the shared temp-file state and the stale/off-screen logic. Each glide could start from the user's cursor or a fixed short offset from the target. Dropping the linger would also cut most of the added latency.

Four of Cubic's P2 threads still apply, all low impact: missing pulse in typeInBackground, tests not pinning the env var, shared temp file across sessions, and unconditional budget for type/fill/scroll. Before merge, please answer those threads and decide whether a default-on 0.65 s per action is acceptable.

@thymikee
thymikee force-pushed the feat/macos-ghost-cursor branch from 4e617c8 to c91f430 Compare October 4, 2026 06:32
@thymikee

thymikee commented Oct 4, 2026

Copy link
Copy Markdown
Member Author

Thanks. Taken in c91f43079:

  • Smaller version. Cross-process persistence is gone: no positionURL, no restoredPosition/persist, no shared temp file. Each glide starts at a short fixed offset above-left of the target.
  • Latency. The linger is gone; the glide is 0.15 s and the pulse 0.12 s, so about 0.3 s per action. That figure is documented in configuration.md and ADR 0031. I kept the cursor on by default because the native backend itself is opt-in and the cursor is how a person watching sees the agent's actions; AGENT_DEVICE_MACOS_GHOST_CURSOR=0 turns it off.
  • SIGTERM. With no linger, a SIGTERM can no longer land after a delivered action.
  • Opt-out test. A case sets AGENT_DEVICE_MACOS_GHOST_CURSOR=0 and asserts no --ghost-cursor in the argv.
  • Budget test. Another case asserts the deadline grows by 1 s only when the cursor is drawn.

The four Cubic threads are answered inline.

@thymikee

thymikee commented Oct 4, 2026

Copy link
Copy Markdown
Member Author

I found no problems at c91f430, and the four earlier findings from the 4e617c8 review (#3195 (comment)) are fixed. Thank you for the quick turnaround. The helper now pulses on all three success paths in typeInBackground, the env opt-out has a test, the shared position file is gone, and the helper timeout adds its extra second only when --ghost-cursor is in argv.

Of the open inline threads, these four are fixed at this head and can be resolved: #3195 (comment) (pulse on success paths), #3195 (comment) (env opt-out test), #3195 (comment) (shared position file) and #3195 (comment) (helper timeout budget).

I did not run the helper live. The glide, the pulse, the screenshot exclusion and the unmoved real pointer rest on reading the code. I also did not confirm that an app-scoped hit test ignores another process's top-level window at the same point.

Smoke Tests is still running on c91f430, and I expect it to be unaffected, because the ghost cursor only applies to the opt-in native app backend. I have not checked that against the job log. There are no conflicts. Once Smoke Tests finishes green, this is ready to merge.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 4, 2026
Each helper action on a native-backend app session draws its own pointer,
glides it onto the target from a short fixed offset, and pulses on
delivery, so a person can follow the agent while keeping the real
pointer. The cursor keeps no state between helper processes and costs
about 0.3 s per action. AGENT_DEVICE_MACOS_GHOST_CURSOR=0 turns it off;
only a drawn cursor adds its budget to the helper deadline.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@thymikee
thymikee force-pushed the feat/macos-ghost-cursor branch from c91f430 to a2a5473 Compare October 4, 2026 08:15
@thymikee
thymikee merged commit 61bf1f0 into main Oct 4, 2026
21 checks passed
@thymikee
thymikee deleted the feat/macos-ghost-cursor branch October 4, 2026 10:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant