The Problem
I run Claude Code and Codex on remote servers over SSH, and I constantly want to say "look at this screenshot" or "check this local file."
Locally, that's just ⌘V or Ctrl+V. Over SSH, it turns into a chore:
- Take a screenshot and save it to a local file first (or dig up the file in Finder)
- Send it to the server with
scp - Type the remote path by hand (and inevitably make typos)
The reverse is just as bad. When an agent replies "I created the report: /home/dev/tmp/report.pdf", I have to retype that path into scp to bring the file back.
I'm usually connected to several remote machines at once, giving instructions to a different agent on each, so I did this all day long and it was driving me up the wall.
Tools Exist for Images, but Not Quite What I Wanted
If all you need is to paste images to an SSH host, there are plenty of good tools: imgssh, clipssh, cc-clip (Japanese), clipaste, claude-ssh-image-skill, and more.
But every one of them only sends clipboard images. I also wanted to send PDFs and folders, and to download logs. Finding a tool that roughly fits, installing it, configuring it, and living with whatever it lacks takes effort. Since I knew exactly what I wanted, I had AI build it instead.
What I Ended Up With
⌘⇧V: From the Mac to the SSH Host
- Take a screenshot to the clipboard (⌘⇧⌃4), or select files or folders in Finder and press ⌘C (multiple items are fine)
- Press ⌘⇧V in a tab connected over SSH
The images, files, or folders land in ~/tmp/ on the remote host, and their full paths are typed into the terminal. They go wherever the cursor is, whether that's a shell or Claude Code's input box, so you can drop them into a command or add a sentence around them and send.
# Transfer and cd in one go
$ cd "/home/dev/tmp/spec_docs"
# Move it wherever you like
$ mv "/home/dev/tmp/spec_docs" spec_docs
⌘⇧D: From the SSH Host to the Mac
Select a path shown on screen with the mouse and press ⌘⇧D, and the file lands in ~/Downloads on the Mac. Folders work too. No need to copy anything.
- Even if the path wraps onto two lines on screen, just select it as is
- If the selection is a URL, it opens in the Mac's browser
Folders and Large Files
- The destination or source is the SSH host the current tab is connected to. Switch tabs to work with a different machine
- Transferring folders or files larger than 10 MB triggers a confirmation dialog and displays a progress window
Making It My Own as I Go
With an off-the-shelf tool, you either adapt to the author's way of thinking or go hunting through settings. When the tool was built just for you, you simply tell the AI on the spot whenever something bugs you. Here are a couple of things I actually said:
"Don't we need to handle macOS dakuten and handakuten?": File names created in Finder can store a character like "パ" decomposed into "ハ" + "゜" (NFD). On Linux, that becomes a different name from the visually identical composed "パ", so I had it convert names to the composed form (NFC) when sending.
"Make it work even when a path wraps and a space sneaks in": When you select a path that the screen has wrapped, it now strips the inserted space and treats it as the correct path.
A general-purpose tool would probably let you choose the download folder in a config file or settings screen, for convenience. But when an AI agent is doing the building, even if it's hardcoded, saying "save it here" is the configuration. There's no need to build a settings feature at all.
How to Use It
The scripts are on GitHub:
archelon-inc/iterm2-ssh-transfer
git clone https://github.com/archelon-inc/iterm2-ssh-transfer.git ~/iterm2-ssh-transfer
1. Assign the Keys
In iTerm2, go to Settings → Keys → Key Bindings, press +, and set up each script like this:
- Keyboard Shortcut: ⌘⇧V and ⌘⇧D (or whatever you prefer)
- Action: Run Coprocess
- The field below it (Enter command to run):
/Users/<your user name>/iterm2-ssh-transfer/upload.shand{same folder}/download.sh
Don't add any arguments. Set the dropdown at the bottom of the editor to apply to the current session only. With "Apply to all sessions", a single key press runs the script in every open tab at once.
2. Let SSH Connect Without Asking for a Password
The scripts open a separate ssh connection in the background, so they can't answer a password prompt. You need ssh to connect without asking for a password or passphrase. A key without a passphrase would work, but that's a bit much, so here's what I do instead.
The first ssh connection you open to a host becomes the "master", and the scripts' ssh connections piggyback on it. Just add this to ~/.ssh/config:
Host *
ControlMaster auto
ControlPath ~/.ssh/cm-%C
- When you run
ssh <host>in a tab, that connection becomes the master. That's the only time you're asked for the passphrase - When the scripts connect in the background, they ride on the master connection, so no further authentication is needed
- Since there's no
ControlPersist, closing the master connection ends the piggybacking. Connecting without authentication only works while the tab is connected - As a bonus, the scripts reuse the existing connection instead of opening a new one, so there's no connection wait, even through a jump host
One quirk: if you connect to the same host from a second tab, it also piggybacks on the first tab. If you then exit in the first tab, it won't finish and keeps waiting until you close the second tab.
3. Raise the Selection Size Limit
Under Settings → Advanced, increase "Maximum number of bytes of selection to provide to Python API". Even if you leave it at the default of 100, ⌘⇧D will tell you with a dialog when you select a long path and open this setting for you.
Caveat: How Far It Reaches
The destination or source is the host you connected to directly from the Mac. It also works through a jump host (ProxyJump) and in tabs using iTerm2's tmux integration (tmux -CC). However, it can't reach a host you ssh into again after logging in to the remote. That ssh runs on the remote host, and the Mac can't see it.
Tested on macOS 27.0.1.
Wrapping Up
Just copy and press ⌘⇧V, or select and press ⌘⇧D. It's surprisingly convenient. Getting a screenshot in front of Claude Code takes a few seconds, and opening files the agent created on my Mac is a breeze.
While writing this, I realized that articles like this used to be mostly about how the thing is implemented. Now that AI does the implementing, that's not very meaningful. So this time I wrote it from the angle of "here's something handy to have AI build for you."
If it looks useful, fork the repository and have AI adapt it to your own environment and taste.
This article was originally published in Japanese at archelon-inc.hatenablog.com.



Top comments (0)