Serve clipboard images to exe.dev VMs over a reverse ssh forward - #61
Open
nonreagent wants to merge 4 commits into
Open
nonreagent wants to merge 4 commits into
nonreagent wants to merge 4 commits into
Conversation
launchd will run it per connection with the socket on stdin/stdout. It answers `types` (is there an image?) and `png` (the bytes, via the same osascript coercion Claude Code uses on macOS, with a TIFF and sips fallback for Preview-style copies) and refuses everything else. No write path, no text path. Stubbed osascript/sips/logger make the test run on Linux too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Socket-activated and inetd-style: launchd owns 127.0.0.1:2224 and spawns clipboard-bridge per connection, so nothing runs while idle. deploy links the plist on Darwin; `make clipboard-bridge` bootstraps or reloads it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A managed ssh include for *.exe.xyz: RemoteForward 127.0.0.1:2224 so the VM's wl-paste shim reaches the launch agent, plus ControlMaster and ControlPersist so every kitty window shares one connection and the forward is requested once, and keepalives so a dead VM does not leave a stale master behind. ~/.ssh/config stays unmanaged; it gains one Include. home/.ssh joins .config in test_deploy.sh's coverage exclusions: it holds an individually deployed file and must never be a whole-directory target. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
On Linux VMs the pipe failed silently on every copy; the earlier copy-selection-and-cancel binding is what we want there, and tmux's set-clipboard already hands the selection to the terminal as OSC 52. test/test_tmux.sh loads the config in a scratch server under both PATHs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
An image on the mac clipboard cannot be pasted into Claude Code running inside tmux on an exe.dev VM. Claude Code on Linux shells out to
xclip/wl-paste, the VM has no display server, and tmux swallows the replies of every in-band terminal clipboard protocol. Separately, the tmuxybinding pipes topbcopyon every host, which fails silently on Linux.Motivation
Agent sessions run remotely in tmux, and a screenshot is the fastest way to show Claude a UI problem. Today that means scp games. exe.dev's gateway was verified to relay reverse ssh forwards, which opens a clean out-of-band path. Design, probes, and the clipfan evaluation:
docs/superpowers/specs/2026-09-07-clipboard-bridge-design.mdin nonreagent/dotfiles#18 (onmainthere once that PR merges).Proposed Solution
Four commits, each independently testable:
home/bin.Darwin/clipboard-bridge: a bash responder that answerstypesandpngfrom the pasteboard viaosascript(TIFF +sipsfallback) and refuses everything else. No write path, no text path. Tested with stubbedosascript/sips/loggerso the suite runs on Linux CI too.home/Library/LaunchAgents/org.nonrational.clipboard-bridge.plist: socket-activated, inetd-style, on127.0.0.1:2224; nothing runs while idle. Deployed via a Darwin manifest row;make clipboard-bridgebootstraps or reloads it.home/.ssh/config.d/exe.conf:RemoteForward 127.0.0.1:2224for*.exe.xyz, plusControlMaster/ControlPersistso windows share one connection and the forward is requested once, plus keepalives. One-time:Include config.d/*.confat the top of~/.ssh/config.home/.tmux.conf:ypipes to pbcopy only where pbcopy exists; elsewhere the plain copy binding stands and OSC 52 does the rest.test/test_tmux.shloads the config in a scratch server under both PATHs.The VM half (a
wl-pasteshim) lands in nonreagent/dotfiles#18.Feedback
ControlPersist 4hkeeps the master and its forward alive;ssh -O exit <vm>.exe.xyzends it early, and a shorterControlPersistshrinks the tail), any VM process can read the mac clipboard image on demand. Text is never served and the bridge has no write path.ControlMaster auto+ControlPersist 4hfor every*.exe.xyzhost is more than the forward: shared connections, a background master for four hours after the last window closes. Comfortable with that?osascriptunder launchd (Claude Code uses the same call; allow once if asked), andlaunchctl bootstrapon a symlinked plist.make clipboard-bridgeprints a confirmation line when the agent loads; ifbootstrapright afterbootoutever returnsBootstrap failed: 5: Input/output error, run it again (or put asleep 1between the two), andlaunchctl print gui/$(id -u)/org.nonrational.clipboard-bridgeis the richer status view. A failed pasteboard read is logged asclipboard info failed: ...under theclipboard-bridgetag, distinct from a text-only clipboard, which logs nothing.make deploy && make clipboard-bridge: with an image on the clipboard,printf 'types\n' | nc 127.0.0.1 2224printsimage/pngandprintf 'png\n' | nc 127.0.0.1 2224 | file -reports PNG image data.