Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sshclip

Tiny native macOS bridge for pasting screenshots into AI agents running on SSH hosts.

sshclip watches your Mac clipboard, and can also process Desktop screenshot files when macOS permissions allow it. When it sees an image, it converts/verifies it as PNG, uploads it to explicit SSH hosts, and replaces your Mac clipboard with the remote path:

/tmp/sshclip-clipboard-20260702-155635-12345.png

Paste that path into Termius, Terminal, Codex, Claude Code, or any remote shell.

Agent Setup Prompt

Paste this into Codex, Claude Code, or another local coding agent on your Mac:

Set up sshclip for me on this Mac.

Use only existing SSH aliases from my ~/.ssh/config. Do not ask for, print, or
store private keys, passwords, tokens, or secrets. If an SSH alias does not work
non-interactively, stop and tell me which alias failed.

Steps:
1. Clone or open this repo:
   https://github.com/heyalerio/sshclip
2. Run ./test.
3. Ask me which SSH alias or aliases to configure, using generic names like
   devbox, staging, or prod in any examples.
4. Verify each alias with:
   ssh -o BatchMode=yes -o NumberOfPasswordPrompts=0 HOST true
5. Install with:
   ./install HOST
6. Pin the default target with:
   sshclip target HOST
7. If I use Termius and want active-tab detection, run sshclip detect-termius
   first and only then set sshclip target termius if the title clearly matches
   one configured SSH alias.
8. Tell me to use Cmd+Ctrl+Shift+4, wait a short beat, then paste in the remote
   terminal. Do not tell me to use Cmd+Shift+4 for the main workflow.

Before finishing, run ./test again and confirm the LaunchAgent is running as
com.sshclip.agent.

Quick Start

  1. Create or confirm an SSH alias:

    Host devbox
      HostName devbox.example.com
      User you

    Tailscale is optional but recommended for private infrastructure. If the SSH host is on your tailnet, keep using a normal SSH alias and point it at the Tailscale name or 100.x.y.z address:

    Host devbox
      HostName devbox
      User you
  2. Confirm SSH works without prompts:

    ssh -o BatchMode=yes -o NumberOfPasswordPrompts=0 devbox true
  3. Install the watcher:

    ./install devbox
  4. Copy a screenshot on your Mac, wait a short beat, then paste in your remote terminal. Use Cmd+Ctrl+Shift+4, not Cmd+Shift+4:

    • Cmd+Ctrl+Shift+4 copies the screenshot image to the clipboard, which is what sshclip watches.
    • Cmd+Shift+4 saves a file on Desktop instead, which is less reliable for a background LaunchAgent because of macOS privacy permissions.

    You should paste text like:

    /tmp/sshclip-clipboard-20260702-155635-12345.png
    

Requirements

  • macOS
  • OpenSSH aliases that already work, for example ssh devbox
  • macOS built-ins only: zsh, osascript, sips, ssh, scp
  • Optional: Tailscale for private-network SSH to hosts

No package manager or background server is required.

Install

./install devbox

The installer creates a LaunchAgent and symlinks:

~/.local/bin/sshclip

Use ~/.local/bin/sshclip directly, or add ~/.local/bin to your shell PATH before using the shorter sshclip command.

Stop and remove the LaunchAgent:

./uninstall

Use

Copy an image or take a screenshot to the clipboard, wait a short beat, then paste in your remote terminal. For macOS screenshots, use Cmd+Ctrl+Shift+4. If you see a Codex/Claude X11 clipboard error, you pasted before the image clipboard was replaced with the remote text path.

Desktop screenshot files are best effort in background mode. macOS privacy controls may prevent a LaunchAgent from seeing ~/Desktop, depending on the machine. If Desktop screenshots do not trigger, use a screenshot-to-clipboard shortcut or run sshclip --once HOST from a terminal that has Desktop access.

Run once instead of watching:

sshclip --once devbox

Termius

Default target is the first configured host. Upload to every configured host only when you explicitly choose all:

sshclip target all

To follow the visible Termius window title:

First check what macOS exposes for Termius:

sshclip detect-termius

Only enable Termius mode if that output contains exactly one configured host alias. If Termius cannot be detected or the title is ambiguous, sshclip does not upload by default.

sshclip target termius

Termius tab/window titles should contain the SSH alias or its compact form:

devbox - frames
staging - logs
prod - codex

For aliases ending in -vps, the compact form also matches. For example, app matches app-vps.

Pin uploads to one host:

sshclip target devbox

Multiple hosts are useful, but target mode all increases disclosure risk because it sends every image to every configured host. After installing more than one host, pin one target or verify Termius detection:

./install devbox staging prod
sshclip target devbox

Security

sshclip is intentionally not a general file uploader.

  • only copied images and ~/Desktop/Screenshot*.png are considered
  • clipboard images are written to a private temp directory and converted to PNG
  • every candidate is rechecked as a regular non-symlink PNG before upload
  • default max upload size is 25 MB
  • remote paths are generated by the script under /tmp
  • uploaded files are sent with mode 0600
  • SSH hosts must be explicit safe aliases passed during install
  • no Termius vault access
  • no command injection into terminal tabs
  • no remote pre-upload shell command
  • no public listener or remote agent

Risks

  • Images are uploaded to every configured host when target mode is all.
  • Anything visible in a copied screenshot may be sent to the selected hosts.
  • SSH aliases are trusted. If an alias points to the wrong machine, the image is uploaded there.
  • Remote files are written under /tmp and are not automatically deleted by this project. The script sends files with mode 0600, but unusual remote filesystems or SSH/SCP implementations may handle modes differently.
  • A remote host with broken SSH/SCP may fail uploads. Other hosts continue.
  • macOS Accessibility may expose different Termius titles than the labels shown inside a terminal pane.
  • target termius requires macOS Accessibility access. Without it, uploads are skipped.
  • Desktop screenshot file watching may require macOS privacy permissions for the shell/LaunchAgent. Clipboard screenshots avoid this issue.

Security Recommendations

  • Review the license and copyright owner before publishing.

  • Use a least-privilege remote user instead of root.

  • Prefer SSH over a private network such as Tailscale when managing many hosts. sshclip does not need Tailscale-specific code; the SSH alias hides that detail.

  • Add remote cleanup, for example a cron job that removes old screenshots:

    find /tmp -maxdepth 1 -type f -name 'sshclip-*.png' -mtime +2 -delete
  • Prefer one or two allowlisted hosts. Large allowlists increase accidental disclosure risk.

  • Keep SSH host key checking enabled. Do not use StrictHostKeyChecking=no.

  • Consider setting a lower max size for teams:

    SSHCLIP_MAX_BYTES=10000000 sshclip devbox

Troubleshooting

Check what would be pasted:

pbpaste

Check Termius detection:

sshclip detect-termius

Check logs:

tail -f ~/Library/Logs/sshclip.log
tail -f ~/Library/Logs/sshclip.err.log

If the clipboard still contains an image, wait briefly and try again. If a host does not receive files, confirm non-interactive SSH and SCP work:

ssh -o BatchMode=yes devbox 'true'
scp screenshot.png devbox:/tmp/sshclip-test.png

If Desktop screenshots are not picked up by the background service, use Cmd+Ctrl+Shift+4 to copy screenshots directly to the clipboard, or run:

sshclip --once devbox

Local Tests

Run the built-in local checks on macOS:

./test

The test script uses macOS built-ins only. It checks shell syntax, command validation, target handling, and unsafe configuration rejection. It does not require real SSH hosts.

To scan for private strings before publishing, pass your own pattern:

PRIVATE_SCAN_PATTERN='old-host|old-user|private-ip' ./test

Configuration

These examples apply to foreground runs:

SSHCLIP_MAX_BYTES=25000000 sshclip devbox
SSHCLIP_POLL=0.2 sshclip devbox
SSHCLIP_UPLOAD_TIMEOUT=8 sshclip devbox
SSHCLIP_CONNECT_TIMEOUT=4 sshclip devbox

Hosts can also come from an environment variable:

SSHCLIP_HOSTS=devbox,staging sshclip

The installed LaunchAgent does not inherit one-off shell environment variables. To change background settings, edit the EnvironmentVariables block in ~/Library/LaunchAgents/com.sshclip.agent.plist, then reload it:

launchctl bootout "gui/$(id -u)" ~/Library/LaunchAgents/com.sshclip.agent.plist
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.sshclip.agent.plist

Logs:

~/Library/Logs/sshclip.log
~/Library/Logs/sshclip.err.log

About

Native macOS clipboard image bridge for SSH terminals

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages