Releases: ShunmeiCho/cc-clip
Release list
v0.11.0
What's New in v0.11.0
Copying out of a remote session now works without you asking it to, Windows paste works in the terminals where it silently did nothing, and Cursor finally tells you when it is done.
Copy on the remote, paste on your machine — no command to remember
v0.10.0 gave you cc-clip copy as an explicit pipe. That was the wrong shape: copying in a remote session does not happen through pipes. You yank in neovim, you hit Enter in tmux copy-mode, you use a TUI's copy action — and all of those invoke xclip or wl-copy, which the shim already sits in front of.
So it now just happens:
" in neovim on the remote
set clipboard=unnamedplus " y / yy / p now cross the SSH boundary# in tmux on the remote
set -g set-clipboard off
bind -T copy-mode-vi Enter send -X copy-pipe-and-cancel 'xclip -selection clipboard -i'The write is forwarded through the tunnel to your local clipboard and replayed into the remote's real xclip, so the remote clipboard behaves exactly as before. Either side succeeding is enough — headless remotes with no real xclip still work. Bytes are verbatim: no terminal rendering is involved, so nothing is soft-wrapped or mangled.
cc-clip copy remains the explicit primitive for pipes. docs/reverse-copy.md covers both configurations and states the boundary honestly: a mouse selection in your local terminal copies what the terminal rendered, no SSH-side process observes it, and no version of cc-clip changes that.
Windows: the paste that reported success and did nothing (#140)
On Electron-based terminals — Wave, Hyper, Tabby, VS Code's integrated terminal — the auto-paste was silently dropped. The upload landed, hotkey.log said send completed, the tray said Image pasted to <host>, the focus guard logged no abort, and the terminal received nothing at all. The keystroke went out through WinForms SendKeys, which Chromium windows ignore outright while SendWait still returns success.
The keystroke is now delivered with SendInput, which those terminals accept, and which reports how many events the input stream actually took — so a refusal (a window running as administrator, for instance) is an error instead of a silent success. It also releases a physically-held ALT/WIN first, so the modifiers of the triggering hotkey no longer merge into the chord.
Two more fixes on the same path:
cc-clip hotkey myserver --no-restore--no-restore was available on send --paste but not on hotkey. It leaves the remote path on the clipboard instead of putting the image back 150 ms later, so on any terminal that still drops synthetic input your own Ctrl+V pastes the right thing. It persists as "no_restore": true in hotkey.json, so it survives the autostart launcher and a reboot.
And cc-clip hotkey --status no longer reports "not running" for a loop that is plainly alive. It identified the process by asking PowerShell for Win32_Process.CommandLine and treated every failure of that lookup — including the empty result you get without rights to read it — as "not our process", then deleted the PID file. One unreadable reading lost the PID permanently: --status said "not running" forever afterwards and --stop could no longer stop the process. Identity now comes from the process image path, and the probe distinguishes gone / not ours / could not tell, reporting the third instead of claiming the loop is down.
Thanks to @Song100Years for a report that diagnosed all three correctly, including the detail that SendWait returns success regardless — which is what made the first one findable at all.
Cursor CLI notifications (#109)
cc-clip connect myserver --cursor--cursor shipped clipboard support in v0.10.0; it now installs a notify hook too, merged into ~/.cursor/hooks.json. Your own hooks in that file are preserved — the stop event keeps every command that is not ours, and a file that will not parse is refused rather than overwritten.
cc-clip doctor covers the notification bridge (#22)
doctor previously stopped at the clipboard path. It now checks the notify nonce, the hook wiring, and the delivery chain, so "notifications stopped working" is a diagnosable state rather than a guess.
Other Improvements
- Windows is now built and tested in CI.
checks.ymlran only onubuntu-latest, which compiles none of the//go:build windowsfiles — the hotkey loop, the tray, every clipboard writer and all of their tests were invisible to every gate, and a break surfaced only when goreleaser cross-compiled at tag time. That is the actual reason the three bugs above shipped. There is now a cross-build + vet step for windows/darwin on both arches, awindows-latesttest job, and a gofmt gate. staticcheckis pinned. It was invoked as@latestagainst a pinned toolchain; when staticcheck raised its own Go floor, CI went red on commits that had changed nothing.main.gosplit intoconnect.go/notify.go/serve.go(#20).- Docs:
docs/reverse-copy.mdis new;docs/commands.mdgains the--cursorrow it never had; the zh/ja READMEs mirror the v0.10.0 feature set. - The daemon no longer prefixes its own clipboard-write notification with
[unverified]. That marker means "this text came from somewhere the daemon cannot vouch for"; spending it on a message the daemon wrote itself is how it stops meaning anything.
Upgrade
Local machine first, then each remote host.
# macOS / Linux, existing install
cc-clip update
# macOS / Linux, fresh install
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh | bash# Windows, install or upgrade
irm https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.ps1 | iexThen, for every remote host:
cc-clip connect <host> --forceThe reverse-copy write shim and the Cursor notify hook are both installed by connect; without this step the remote keeps the old shim and nothing above changes for that host.
Windows users on the hotkey path should re-run cc-clip hotkey <host> --enable-autostart so the loop restarts on the new binary.
Not in This Release
- The Windows paste fix is not verified on real hardware. There is no Windows machine behind this release. The new
windows-latestjob runs the Windows-only unit tests for the first time, but whetherSendInputactually pastes into Wave is unconfirmed — please report on #140 either way. If it still does nothing for you,--no-restoreis the fallback that works regardless. - Cursor notifications are not verified against a real
cursor-agent. Cursor's CLI hook support has a history of firing unevenly, and cc-clip records this adapter as installed-but-unverified for that reason. Reports welcome on #109. - Mouse selection in your local terminal still does not reverse-copy, and cannot — see
docs/reverse-copy.mdfor why and for the two configurations that do work. - Reverse image copy is still unimplemented (#128); no motivating case yet.
- Persistent per-host SSH tunnels (#108) and notification icon/sound settings (#92) remain open.
Verification
V=0.11.0
gh release download "v$V" --repo ShunmeiCho/cc-clip \
--pattern "cc-clip_${V}_darwin_arm64.tar.gz" --pattern "checksums.txt"
shasum -a 256 -c checksums.txt --ignore-missingFull Commit List
98f2addfeat(notify): Cursor CLI notifications via ~/.cursor/hooks.json (#109)41f6c5edocs: --no-restore does not stop the keystroke, it makes it optionalfa172c4docs: reverse-copy guide, and stop labelling our own notification unverified (#128)9f083a6fix(windows): deliver paste with SendInput, add hotkey --no-restore, stop losing the PID file (#140)906bba1feat(shim): transparent reverse copy — clipboard writes land locally (#128 phase 2)6ed1699docs(i18n): mirror v0.10.0 features to zh/ja READMEs7694090docs: README tagline covers Cursor and reverse copy7b477fbfeat(doctor): cover the notification bridge (#22 P1)041fbcerefactor: split main.go into connect.go / notify.go / serve.go (#20 I1)
Full diff: v0.10.0...v0.11.0
v0.10.0
What's New in v0.10.0
Three features. Two of them close long-standing gaps in what the tunnel could carry; the third stops cc-clip from replacing binaries a package manager owns.
cc-clip copy — the clipboard now runs both ways
Copying text out of a remote CLI by mouse selection copies what the terminal rendered: a long command soft-wrapped at the terminal width comes out with hard newlines at every visual break. That path is unfixable — the mangling happens in your terminal emulator. So cc-clip now bypasses it entirely:
cat deploy.sh | cc-clip copy # on the remote: bytes land on your LOCAL clipboard verbatim
fc -ln -1 | cc-clip copy # copy the command you just ran, wrap-freePiped text never touches terminal rendering, so embedded and trailing newlines survive exactly. Auth rides the existing Bearer token; the body is capped at CC_CLIP_MAX_TEXT_MB (default 1MB).
Every accepted write raises a calm local notification ("A remote session copied N bytes to this clipboard"). That is deliberate and not configurable off in this release: a remote that can write your clipboard is a paste-hijack primitive, and silent writes are the failure mode. The notification names the byte count, never the content.
Cursor CLI target (#109)
cc-clip setup myserver --cursorCursor's clipboard reader shells out to xclip/wl-paste in shapes the shim already intercepts, so image paste works with no new transport. One prerequisite the deploy cannot satisfy: Cursor only reads the clipboard when DISPLAY or WAYLAND_DISPLAY is set in its shell (echo $DISPLAY to check; ssh -X or export an existing display). cc-clip deliberately does not invent one — a DISPLAY with no X server behind it would break clipboard fallback for every other tool in that shell. The setup output explains this, plus a timeout tweak for large images. Cursor notifications are not wired up yet.
Package-managed remote binaries — --use-remote-bin (#110)
Contributed by @Qu4tro. If nix, home-manager, pipx, or your distro's package manager owns cc-clip on the remote, cc-clip setup myserver --use-remote-bin keeps it that way: the executable is resolved under your remote login shell's PATH (so user-profile package managers are actually found), fingerprinted, and used as-is — nothing is uploaded. The mode is remembered in the host's deploy state, so later connect runs (including the connect <host> --force line cc-clip update suggests) keep it without the flag; deploy with --local-bin to switch back.
cc-clip status now catches a stale daemon
Replacing the binary in place never restarted the launchd service, so the running daemon could silently lag your binary — the reason past release notes had to insist on cc-clip update over a manual copy. /health now reports the daemon's version and cc-clip status warns when they provably differ, with the restart command. No warning is printed when honesty is impossible (pre-v0.10.0 daemon, dev build) — a false "stale daemon" warning would teach you to ignore the real one.
Behavior notes
- New notification after remote copies. "Clipboard set by remote" appearing after you run
cc-clip copyis the feature working, not noise — see above. cc-clip copyagainst an old local daemon fails with instructions. If the local machine still runs a pre-v0.10.0 daemon, the remote command reportsthe daemon does not support clipboard write; upgrade cc-clip on the local machine and restart it (cc-clip update). Upgrade order below.- Remote deploy state moves to schema v2 (it now records the package-managed mode). A machine still running v0.9.x cc-clip that connects to a host deployed by v0.10.0 will refuse to overwrite that state without
--force— intentional, so an older binary cannot silently strip the new marker.
Upgrade
Order matters this time: local first, then each remote host.
# 1. Local machine — also restarts the daemon (required for cc-clip copy and the version field)
cc-clip update
# 2. Each remote host — the binary hash changed, so connect re-uploads automatically
cc-clip connect myservercc-clip copy needs both ends on v0.10.0: the remote binary provides the command, the local daemon provides the endpoint. Fresh installs: install.sh (macOS/Linux) / install.ps1 (Windows) as usual.
Not in This Release
- Shim interception of clipboard writes (
xclipwithout-o,wl-copy), which would land remote TUIs' own copy actions on your local clipboard — #128 phase 2. - Cursor notifications — tracked on #109, awaiting real-host confirmation of the
--cursortarget. doctorcoverage of the notification bridge — #22's last open item.- Managed persistent per-host SSH tunnels — #108, design agreed, implementation in progress by @paigeman.
- Per-tool notification sounds/icons — #92, pending a config-format decision.
Verification
V=0.10.0
PLATFORM=darwin_arm64 # or darwin_amd64, linux_amd64, linux_arm64
curl -fsSLO https://github.com/ShunmeiCho/cc-clip/releases/download/v${V}/cc-clip_${V}_${PLATFORM}.tar.gz
curl -fsSLO https://github.com/ShunmeiCho/cc-clip/releases/download/v${V}/checksums.txt
shasum -a 256 --ignore-missing -c checksums.txtFull Commit List
a1e63f4docs: the /health version field ships in v0.10.0, not v0.9.3 (#134)d379ecftest: lift cmd/cc-clip coverage past the 30% target (#20 I4) (#133)69c79d5feat: daemon version consistency check and LocalCommand docs (#22 P2+P3) (#131)95839e2feat: cc-clip copy — reverse clipboard, remote stdin to local clipboard (#128) (#129)dc5d049feat: add Cursor CLI deployment target (#109) (#126)982195cfeat: support package-managed remote binaries (#111)1ec2b0bdocs: record the remote PATH prelude pitfall (#125)543dc35ci: gate the release on the same checks CI runs (#123)
Full diff: v0.9.2...v0.10.0
v0.9.2
What's New in v0.9.2
A correctness release. Two of the three fixes make cc-clip report problems it previously hid — if a new warning appears right after upgrading, please read "If you see a new message" below before assuming this release broke something.
Fixes
-
Windows paste no longer fires into the wrong window (#43, #115):
cc-clip send --pasteand theAlt+Shift+Vhotkey put the remote path on the clipboard, wait, then synthesizeCtrl+Shift+V— which went to whatever window was focused at that moment. The gap was wider than--delay-ms, because a fresh PowerShell process has to start first. Switching windows in that gap delivered the remote path into whatever you switched to: a password manager, a chat input, a browser URL bar. cc-clip now records the focused window before touching the clipboard, re-checks it before the keystroke, and aborts without typing anything if it moved — or if Windows reports no foreground window at all, which happens briefly while a window is losing activation. -
The tunnel check now proves the daemon is actually there (#22, #114):
cc-clip connectandcc-clip doctordecided the tunnel was healthy from a bare TCP handshake. Ansshdleft over from a previous SSH session keeps the forwarded port open after its client is gone, so the handshake succeeded while nothing reached the daemon — and cc-clip printedtunnel verifiedfor a tunnel that carried nothing. Both commands now ask the daemon to identify itself through the forward viaGET /health, and distinguish five outcomes instead of two: healthy, nothing listening, port held but no daemon answering, reachable-but-unverifiable, and check-did-not-complete. Only a daemon that answers counts as healthy. -
/notifysays which authentication step failed (#20, #116): a missingAuthorizationheader, a malformed one, and a genuinely invalid nonce all returned the sameinvalid notification nonce, so~/.cache/cc-clip/notify-health.logcould not tell them apart. Each now has its own message. This also closes a parsing gap: anAuthorizationheader carrying a bare nonce without theBearerprefix used to be accepted, and is now rejected. Every cc-clip component already sends theBearerform, so only hand-rolled senders are affected.
If you see a new message
WARNING: port 18339 is held on the remote, but no cc-clip daemon answered.
Your tunnel was already not working; v0.9.1 called it tunnel verified anyway. The message names both causes: a stale sshd still owning the forward — lsof -ti tcp:18339 on the remote — or a live forward with no local daemon running (cc-clip serve).
One false alarm to know about: a local daemon still running a v0.7.7-or-older build is also reported as stale, even when the tunnel is fine. Those builds answer /health with {"status":"ok"} and no service field, which is what the new check matches on (the field was added in v0.8.0). Restarting the daemon on the new binary clears it — cc-clip update does this for you.
focus changed during paste; paste aborted, nothing was typed
The paste was withheld on purpose and nothing reached the other window. Re-focus the target window and press the hotkey again.
port 18339 reachable but daemon liveness unverified (no curl on remote)
The remote has no curl, so the daemon could not be asked to identify itself. This is not a clipboard failure — install curl on the remote for a real verification.
Behavior changes worth checking if you script around cc-clip
cc-clip send --pastenow exits 1 on a focus abort, after already printing the remote path to stdout. The upload succeeded and the remote file exists; only the paste was withheld.- The
connectsuccess line changed fromtunnel verified (via existing SSH session)totunnel verified (cc-clip daemon answered through the existing SSH session). cc-clip doctornow skips the end-to-end image probe unless the tunnel check is fully OK, so on a broken tunnel the failing row moves fromimage-probetotunneland theimage-proberow disappears.
Other Improvements
- The vulnerability scan in CI now runs against the current Go release instead of the pinned
go.modfloor. Previously every new Go standard-library advisory turned CI red with no source change — that happened twice in three days (#113, #119). - CI now enforces the existing
.gitignorerule keeping per-machine agent tool configuration (.claude/,.codex/,.agents/,AGENTS.md) out of the repository (#120). docs/windows-quickstart.mdanddocs/troubleshooting.mdno longer teach the bare TCP tunnel check that #114 removed for being wrong (#122).CLAUDE.mdcorrected to describe the settings-first Claude hook path accurately (#84, #117).- READMEs redesigned and shortened in all three languages. Documentation only.
- Go floor moved to 1.25.13. This affects source builds only (
make build,go install, andconnect's cross-compile fallback), and only withGOTOOLCHAIN=localon an older Go. Release binaries andcc-clip updateare unaffected.
Upgrade
macOS / Linux, existing install:
cc-clip updatePrefer this over replacing the binary by hand. The /notify fix lives in the daemon and only takes effect once the daemon restarts; cc-clip update reinstalls the service (with rollback if the new binary fails to come up), while an in-place copy leaves the old daemon running.
macOS / Linux, fresh install:
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh | shWindows:
irm https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.ps1 | iexRemote hosts: no redeploy required. Nothing installed on the remote changed in this release — not the shim, the hook script, the settings hooks, nor the X11 bridge. Re-running cc-clip connect <host> --force is optional and will simply re-upload the binary.
Not in This Release
- Package-managed remote binaries (
--use-remote-bin) — #110, implementation under review in #111. - Managed persistent per-host SSH tunnels — #108, design agreed, phased implementation pending.
- Cursor CLI support — #109, blocked on a
DISPLAYdesign decision. - Per-tool notification profiles (sound and icon per CLI) — #92, follow-up to the global settings shipped in #95.
- Automatic cleanup of a stale remote
sshd— #22 deliberately stops at precise diagnosis. Killing a remotesshdthat cc-clip cannot positively identify as its own is a worse failure mode than telling you exactly what to end. cc-clip doctorcoverage of the notification bridge — #22, still open;doctorcurrently checks the clipboard path only.
Verification
V=0.9.2
PLATFORM=darwin_arm64 # or darwin_amd64, linux_amd64, linux_arm64
curl -fsSLO https://github.com/ShunmeiCho/cc-clip/releases/download/v${V}/cc-clip_${V}_${PLATFORM}.tar.gz
curl -fsSLO https://github.com/ShunmeiCho/cc-clip/releases/download/v${V}/checksums.txt
shasum -a 256 --ignore-missing -c checksums.txtFull Commit List
1579564docs: align tunnel troubleshooting with the health probe (#22 P0 follow-up) (#122)b8a8b90docs: correct CLAUDE.md notification-path and hook-injection pointers (#84) (#117)b6d466cfix(daemon): distinguish /notify auth failure classes (#20 I3) (#116)0184d8dfix(windows): abort paste when focus moves between copy and keystroke (#43) (#115)942b584fix(tunnel): verify daemon liveness instead of TCP reachability (#22 P0) (#114)deb5e95ci: scan with current Go, and enforce the agent-config gitignore policy (#120)fe13d28fix(ci): bump Go floor to 1.25.13 to clear GO-2026-6089/6090/6218 (#119)5958436fix(ci): bump Go floor to 1.25.12 to clear GO-2026-5856 (#113)becdae8docs(i18n): sync redesigned README translationse0d18e6docs: redesign and streamline README80cbb6echore(release): group changelog into Features/Fixes (#107)
Full diff: v0.9.1...v0.9.2
v0.9.1
What's New in v0.9.1
Fixes
- N0 v0.7.0 detection is now robust on minimal SSH environments (#101, #106):
cc-clip connectno longer aborts withexit 127when coreutils (readlink/head/grep/wc/tr) aren't on the non-interactive SSHPATH(e.g. Coder workspaces, slim containers).PATHhardening now applies to every remote command viaWrapRemoteShell, and detection fails closed only when it cannot verify a remote is uncorrupted. - Image-transfer notifications are deduplicated (#100): rapid re-fetches of the same clipboard image (clipboard managers, agent retries) no longer spam notifications — duplicates within a short window are suppressed by
(session, fingerprint). cc-clip updateauthenticates withGITHUB_TOKEN/GH_TOKEN(#104): avoids GitHub API403rate-limit failures oncc-clip update --check.- Clearer Codex notify errors (#104): the notify-config refusal reason is surfaced instead of a bare
exit status 7. - Post-update redeploy reminder defaults to
--all --force(#104): preserves the Claude shim on Codex hosts instead of suggesting--codex(which is Codex-only since v0.9.0). Codex-only users are pointed at--codex --force.
Experimental
- Windows direct clipboard transport.
The auto-generated ECC bundle briefly merged in #99 was reverted in #102 — no user-facing change in this release.
v0.9.0
What's New in v0.9.0
cc-clip now adds per-target setup, expands clipboard support across remote CLI workflows, and wires notifications for Claude Code, Codex CLI, opencode, and Antigravity.
Highlights
- Per-target setup. Pick what each host gets:
--claude/--codex/--opencode/--agy, or--allfor everything. ⚠️ Breaking change —--codexis now Codex-only. In v0.8.x,--codexadded Codex on top of the Claude shim. In v0.9.0 it installs Codex only — use--allto get both Claude and Codex on one host.- Notifications for more CLIs. Notification wiring now covers Codex CLI, opencode, and Antigravity, alongside Claude Code. (opencode/Antigravity integrations are installed during
connect; end-to-end delivery is not yet host-smoke-verified. Antigravity is notify-only — no clipboard transport.) - Configurable notification sound tiers and a terminal-notifier app icon (#92, #95).
- Safer cross-version deploys. A
schema_versionforward-downgrade guard stops an older cc-clip from silently clobbering a newer remote's deploy state. - Remote commands run under POSIX
/bin/shregardless of the login shell (#98).
Upgrading from v0.8.x
--codex changed meaning (see above) — use --all for Claude + Codex. Full migration notes: Upgrading from v0.8.x to v0.9.0.
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh | shOn a v0.9.0 beta? Same feature set as stable — run cc-clip update to move to v0.9.0. If you pinned CC_CLIP_VERSION=v0.9.0-beta.x, drop the pin.
Changelog
- eaea0a5 docs(i18n): mirror v0.9.0 stable docs to zh/ja READMEs
v0.9.0-beta.2
cc-clip v0.9.0-beta.2 (prerelease — opt-in)
⚠️ Beta / opt-in prerelease. GitHub's latest-release API only returns non-prerelease releases, so neither the defaultinstall.shnorcc-clip updatewill hand you this build —v0.8.1stays the stable default. You only get beta.2 by explicitly pinning the version below.
Incremental prerelease on the v0.9.0 line. It carries everything from v0.9.0-beta.1 (the large connect/setup deployment refactor, per-target setup, opencode & Antigravity notifications) — see those notes for the full v0.9.0 picture and rollback guidance — plus the changes below.
What's new since v0.9.0-beta.1
- fix(connect): remote commands now run under POSIX
/bin/shregardless of login shell (#98). On hosts whose login shell is fish (or any non-POSIX shell),connect/send/doctorpreviously died with exit 127 because fish mis-parses the sh scripts cc-clip sends over SSH. Every remote command is now wrapped in/bin/sh -c '…', so it runs correctly no matter which shell sshd invokes. bash/zsh logins are unchanged. - feat(notify): configurable notification sound tiers + terminal-notifier app icon (#95). Notification urgency now maps to distinct sound tiers, and macOS notifications carry a proper app icon.
- docs: beta references aligned to
v0.9.0-beta.2across README (en/zh/ja) and the command / notification reference docs.
Install (opt-in prerelease)
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh | CC_CLIP_VERSION=v0.9.0-beta.2 shcc-clip --version should then report v0.9.0-beta.2. Stable users are unaffected.
Changelog
v0.9.0-beta.1
cc-clip v0.9.0-beta.1 (prerelease — opt-in)
⚠️ Beta / opt-in prerelease. This release must be published as
v0.9.0-beta.1so GoReleaser marks it as a GitHub prerelease. GitHub's
latest-release API returns only non-prerelease, non-draft releases, so neither
install.sh(default) norcc-clip update(default) will hand you this build.
You only get it by explicitly pinning the version below. Please read
Rollback first.
Why a beta
v0.9.0 is a large connect/setup deployment refactor. Instead of one person
exhaustively probing every remote environment, this prerelease invites testing
across diverse real setups. Bug reports (template at the bottom) are the whole
point of this build.
Install (opt-in)
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh \
| CC_CLIP_VERSION=v0.9.0-beta.1 sh
Quick start (after install)
- Make sure
cc-clipis on your PATH — the installer prints the line to add to your
shell profile (e.g.export PATH="$HOME/.local/bin:$PATH"), then reload your shell. - Set up a remote host (pick the target for your CLI):
- Claude Code only:
cc-clip setup <host> - Claude Code + Codex CLI:
cc-clip setup <host> --all(Codex needs Xvfb + sudo on the remote) - Codex CLI only:
cc-clip setup <host> --codex(needs Xvfb + sudo) - opencode only:
cc-clip setup <host> --opencode - Antigravity (agy) only:
cc-clip setup <host> --agy
- Claude Code only:
- Open a NEW SSH session (the tunnel activates on connect):
ssh <host> - Copy an image to your local clipboard, then press
Ctrl+V(or your agent's paste key)
in the remote CLI. - Verify end-to-end any time:
cc-clip doctor --host <host>
Full walkthrough (prerequisites, Codex specifics, Windows) — see the README Beta Quick Start:
https://github.com/ShunmeiCho/cc-clip#beta-quick-start-opt-in-v090-beta1
Rollback (if anything breaks)
cc-clip update --to v0.8.1
# or
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh \
| CC_CLIP_VERSION=v0.8.1 sh
As a beta user, prefer --to <tag> for any version change. A bare cc-clip update
follows /releases/latest (stable) and will move you OFF beta.
What's New
⚠️ BREAKING: --codex now installs Codex support ONLY
Previously --codex layered Codex on top of the Claude shim. It now installs
only Xvfb + x11-bridge (no Claude shim). For Claude Code and Codex on the
same host, use --all. Default (no flag) and --claude install the Claude shim.
An existing shim is never removed. A one-time deprecation notice prints on legacy
--codex; silence it with CC_CLIP_NO_DEPRECATION_NOTICE=1.
Multi-target connect / setup
Explicit deployment targets: --claude, --codex, --opencode, --agy, and
--all. One target per run, or --all for everything. (Free combinations like
--claude --codex together are NOT in this beta — see Known limitations.)
Notify bridge: opencode + Antigravity (agy)
- opencode: clipboard paste already worked via the xclip/wl-paste shim;
--opencodenow also forwards opencodesession.idleevents as native
notifications. - Antigravity (agy):
--agyinstalls theagy-notifyplugin (notify-only).
Deployment-resilience safety net (new in this build)
- deploy-state
SchemaVersion+ connect forward-downgrade guard (an older
cc-clip refuses to clobber a newer-schema remote). uninstall --codexaborts against a newer-schema remote (no silent clobber).CC_CLIP_VERSIONinstall pinning = the rollback channel above.- sha256 checksum verified before cross-arch binary extraction.
Known limitations in this beta
- Multi-target free combinations (e.g.
--claude --codex) are not released
yet — single target or--allonly. - Antigravity (agy): notify-only; clipboard paste not yet implemented.
connect --forcefull-deploy path is not yet covered by a live-remote smoke.
(Theuninstall --codexnewer-schema guard IS live-verified on a real host;
connect --forceis covered transitively + unit tests.)
Roadmap — where cc-clip is heading
Direction and priorities, not dated commitments. Order roughly reflects priority, not schedule.
- Harden the v0.9.0 refactor (P1): live-remote coverage for
connect --force,
and anSSHSessiontest seam so deploy/uninstall orchestration is easier to test. - Multi-target free combinations (for example,
--claude --codextogether):
under design; today target selection is one target or--all. - Antigravity (agy) clipboard paste: currently notify-only. Clipboard support
needs real transport confirmation before implementation. - Easier distribution (P2):
npm/npxentry + per-platform packages, so
users have an alternative to the shell installer. This should be trialed in a
separate beta first. - Docs: slim the README and move detailed workflows into focused docs.
- Windows parity: reduce the gap between current Windows support and the
native shim/update experience.
Principles we hold
- Transparent & opt-in — intercept only the agent-specific calls cc-clip needs;
prerelease builds are opt-in and are not returned by GitHub's latest-release API. - Security-first — loopback-only daemon, token + per-session nonce auth, and
careful handling of secrets. - Reversible release installs — use
CC_CLIP_VERSIONorcc-clip update --to
to move back to a known good version; schema guards avoid silently clobbering a
newer remote state. - Fresh, not cached — clipboard transport fetches the current image on demand.
Help shape it — we want your input
This beta exists to learn from real environments. Tell us what to prioritize:
- Which remote CLI should we support or harden next?
- What is rough in
setup/connecton your local OS + remote OS combination? - What would make daily use smoother?
Open or upvote a thread in
Discussions, or file an
Issue. A 👍 on an existing item
is a useful signal and helps us rank the backlog.
When reporting a beta issue, please include:
cc-clip --version- local OS and remote OS
- the target flag used (
--claude,--codex,--opencode,--agy, or--all) - relevant CLI versions (
claude,codex,opencode,agy) cc-clip doctor <host>output- remote
~/.cache/cc-clip/deploy.jsonif relevant, with host-specific details redacted
v0.8.1
v0.8.0
cc-clip v0.8.0
A reliability round for the notification bridge and the send path, plus a new notification sound. Resolves #81 and #82; partially hardens #80 (see note).
Highlights
Notification sound (#81)
- New
cc-clip notify --sound <name>mapping to macOS system sounds (Glass, Ping, Basso, ...). Unknown names are ignored (never passed raw to the notifier). --urgency 2(critical) now plays a default Glass chime, including on the hook path (e.g. permission prompts).- First-use note: macOS may prompt to allow notifications for
terminal-notifier; grant it, or the system suppresses the banner and sound.
Reboot-stable notifications (#82.2 / #82.3)
- The daemon's notification-nonce registry is now persisted to disk (mode 0600, atomic write) and reloaded on startup, so a Mac reboot or daemon restart no longer breaks notifications with HTTP 401 — no manual reconnect required.
--token-onlynow also re-syncs the notification nonce.
More robust hook injection (#82.1 / #82.4)
- The claude wrapper injects Stop/Notification hooks unconditionally (no more launch-time tunnel race);
cc-clip-hookis fail-soft when the tunnel is down. - New persistent opt-out:
cc-clip connect --no-hooks(and--hooksto re-enable). The marker survives wrapper reinstalls and--force, for users who manage hooks themselves.
Clean custom notifications (#82.5)
cc-clip notify --trustedsuppresses the[unverified]prefix for nonce-authenticated local callers.- The Notification hook path now renders the
messagefield as the body, so custom-text notifications are no longer empty.
Hardened upload verification (#80, partial)
cc-clip sendnow verifies the remote file size after upload and fails loudly (non-zero exit) on empty / missing / size-mismatch.- Note: this does NOT yet cover the wrong-path case reported in #80, where an SSH banner/warning pollutes the remote
$HOMElookup so the file lands at a wrong path with the correct size. Root cause (stdout/stderr isolation in the remote-home lookup) is tracked for v0.8.1.
Project hardening
- PR-level CI (build, vet, race tests, staticcheck, govulncheck) plus assorted correctness and atomicity fixes.
Known limitations
- The wrapper-based hook injection can be wiped by Claude Code's own self-update (it rewrites the
~/.local/bin/claudesymlink). Durable hook installation via a~/.claude/settings.jsonmerge or a plugin is tracked in #84. If you keepcc-clip-hookin your own~/.claude/settings.json, that path is durable today. sendwrong-path under SSH banner pollution (#80) — fix tracked for v0.8.1; workaround: addLogLevel QUIETto~/.ssh/config.
Upgrade
cc-clip update- Restart the daemon (macOS):
cc-clip service uninstall && cc-clip service install - Redeploy to remote hosts:
cc-clip connect <host> --force
Full diff: v0.7.7...v0.8.0
v0.7.7
Patch release tightening the section-aware notify detector introduced in v0.7.6. Backward compatible. Recommended for users whose Codex config uses indented sub-tables.
Fix since v0.7.6
fix(shim): allow indented [section] headers in codex notify detector
v0.7.6's awk used /^\[/ to identify TOML section headers, matching only column-0 headers. But TOML 1.0.0 §Table treats leading whitespace on a section header line as whitespace and ignores it, so a perfectly legal [agents.X] was silently skipped — and any notify = beneath it was mis-classified as top-level, falsely tripping exit 7.
Fix: tighten the regex from /^\[/ to /^[[:space:]]*\[/, matching the symmetric [[:space:]]* tolerance already in place for the notify line itself.
- /^\[/ { in_section = 1; next }
+ /^[[:space:]]*\[/ { in_section = 1; next }Regression coverage
TestEnsureRemoteCodexNotifyConfigAllowsIndentedAgentSectionNotify — fixture contains a TOML body whose [agents.docs_researcher] block is indented; asserts the top-level injection succeeds and the agent-level notify is preserved verbatim. Without the fix this test fails with exit status 7.
Upgrade
curl -fsSL https://raw.githubusercontent.com/ShunmeiCho/cc-clip/main/scripts/install.sh | bashOr, if you already have cc-clip installed:
cc-clip updateVerification
sha256sum -c checksums.txt --ignore-missing