Paste images into remote Claude Code, Codex CLI, and opencode sessions over SSH.
Optional integrations bring completion and approval notifications back to your desktop.
Quick start · Choose a target · How it works · Documentation
Install → setup → open SSH → paste.
Upgrading from v0.8.x? In v0.9.0,
--codexbecame Codex-only. Use--allwhen the same host also needs the Claude integration. See the upgrade guide.
This is the stable macOS-to-Linux path. You need:
- macOS 13 or later;
- a Linux remote (amd64 or arm64) with
curl,bash, andxcliporwl-paste; - a named
Hostentry in~/.ssh/config.
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh | sh
cc-clip --versionIf the installer asks, add ~/.local/bin to your PATH before continuing.
cc-clip setup myserverThe default target is Claude Code. Setup checks local dependencies, adds the
loopback RemoteForward, starts the local daemon, and deploys the remote shim.
Use a target flag from the next section for Codex, opencode, or notifications.
ssh myserverStart your coding agent and paste as usual. The new SSH connection is important: it is what holds the reverse tunnel open.
Copy an image to the Mac clipboard, then run locally:
cc-clip doctor --host myserverChoose one selector per setup. With no selector, cc-clip configures Claude Code.
| Remote workflow | Setup command | Image paste | Desktop notifications | Extra requirement |
|---|---|---|---|---|
| Claude Code | cc-clip setup myserver |
Yes | Yes | xclip or wl-paste |
| Codex CLI only | cc-clip setup myserver --codex |
Yes | Yes | Xvfb; setup may need remote sudo |
| All integrations | cc-clip setup myserver --all |
Yes | Yes | Xvfb for Codex |
| opencode | cc-clip setup myserver --opencode |
Yes | Yes | xclip or wl-paste |
| Antigravity | cc-clip setup myserver --agy |
No | Yes | Notification integration only |
For Codex targets, cc-clip tries to install Xvfb with apt or dnf. If
passwordless sudo is unavailable, it stops and prints the exact install command;
run that command manually, then repeat setup.
The Claude and opencode paths use the remote xclip or wl-paste shim. Codex
reads X11 directly, so its target adds Xvfb and cc-clip x11-bridge instead.
opencode and Antigravity integration generation is covered by tests, but host event delivery has not yet been smoke-tested on a representative machine. Please report what you find.
| Local machine | Remote | Support level | Recommended path |
|---|---|---|---|
| macOS 13+ | Linux | Stable | cc-clip setup HOST |
| Windows 10/11 | Linux | Experimental | send / hotkey quick start |
| Linux | Linux | Manual daemon | Run cc-clip serve, then cc-clip setup HOST in another shell |
Windows support remains experimental. Start with the explicit upload-and-paste workflow in the Windows Quick Start. v0.9.1 also includes an opt-in direct RemoteForward transport, but it is not the default.
cc-clip keeps the transport narrow and local to your SSH connection:
Image paste
local clipboard
→ cc-clip daemon on 127.0.0.1:18339
→ SSH RemoteForward
→ remote xclip/wl-paste shim or Xvfb bridge
→ remote coding agent
Notifications
remote hook / notify command / plugin
→ SSH tunnel
→ local cc-clip daemon
→ macOS Notification Center or cmux
- The local daemon reads clipboard data only when the remote side asks for it.
- SSH exposes that daemon on remote loopback; no public listener is created.
- Claude Code and opencode reach it through a transparent clipboard shim.
- Codex reaches it through an Xvfb clipboard owner because Codex reads X11
directly instead of invoking
xclip. - Unrecognized
xclip/wl-pastecalls fall through to the real remote tool.
Clipboard data and agent events share the SSH tunnel but use separate
authentication material. cc-clip connect can wire:
| Source | Integration | Example event |
|---|---|---|
| Claude Code | Managed hooks | Stop, approval request, image paste |
| Codex CLI | notify command |
Task completion |
| opencode | Generated plugin | Session idle |
| Antigravity | Generated plugin | Agent stop |
For adapter details, manual configuration, nonce registration, and diagnostics, see SSH Notifications.
| Boundary | Protection |
|---|---|
| Network | Daemon and forwarded port bind to loopback only |
| Clipboard | Bearer token with 30-day sliding expiration |
| Notifications | Separate per-connect nonce |
| Process list | Tokens and hook payloads are not placed in command-line arguments |
| Fallback | Unrelated clipboard calls pass through to the real remote binary |
Loopback is shared by users on the same remote host. The token file is mode
0600, but cc-clip does not defend against another process acting as your Unix
account or reading your files. Read the explicit threat model
before using cc-clip on a shared or untrusted host.
| Command | Use it for |
|---|---|
cc-clip setup HOST [target] |
First-time dependencies, SSH config, daemon, and deploy |
cc-clip connect HOST --force [target] |
Repair or fully redeploy a host |
cc-clip connect HOST --token-only |
Sync a rotated or expired token |
cc-clip doctor --host HOST |
End-to-end diagnosis |
cc-clip status |
Local component status |
cc-clip hosts list |
Known-host registry |
cc-clip update --check |
Check the published release channel |
cc-clip update |
Install the latest published release |
Run cc-clip --help for the authoritative command list. The
commands guide covers the common flags and environment
variables.
| Setting | Default | Environment variable |
|---|---|---|
| Tunnel port | 18339 |
CC_CLIP_PORT |
| Token lifetime | 30d |
CC_CLIP_TOKEN_TTL |
| Debug logging | off | CC_CLIP_DEBUG=1 |
Start with the built-in diagnosis:
cc-clip doctor --host myserverThe three most common fixes are:
- Tunnel unavailable: keep a fresh
ssh myserversession open. ARemoteForwardexists only while an SSH connection owns it. - Token rejected after daemon restart: run
cc-clip connect myserver --token-only. - Codex has no clipboard: open a new SSH session so the injected
DISPLAYis loaded; if Xvfb or x11-bridge is missing, runcc-clip connect myserver --codex --force(or--all --force).
If a new SSH tab reports remote port forwarding failed for listen port 18339,
another live or stale SSH session already owns the fixed remote port. Use the
working session, close the old one, or follow the port cleanup steps in the
Troubleshooting Guide.
Use a simpler option when it fits:
- use an editor's built-in remote clipboard if your whole workflow is already inside that editor;
- use OSC 52 for text-only clipboard synchronization;
- use
scpwhen image transfer is rare and preserving paste behavior is not worth a daemon and SSH forward; - use a general clipboard bridge when you need broad, bidirectional clipboard synchronization rather than a narrow agent workflow;
- avoid cc-clip on an untrusted shared host where remote local users must not reach your user-scoped loopback tunnel.
| Guide | What it covers |
|---|---|
| Windows Quick Start | Windows upload, paste, and hotkey workflow |
| Upgrading | Breaking changes and version-specific migration |
| Commands | Common commands, flags, and environment variables |
| Notifications | Hook and plugin integrations |
| Troubleshooting | Symptom-by-symptom diagnosis |
| Security | Threat model and trust boundaries |
Bug reports and focused pull requests are welcome. For larger features, open an issue first so the approach can be discussed.
Building from source requires the Go version declared in go.mod:
git clone https://github.com/ShunmeiCho/cc-clip.git
cd cc-clip
make build
make testUse Conventional Commits for commit
messages (feat:, fix:, docs:, and so on).