Native clipboard access for Go with secret-aware writes and auto-clear support. Linux, macOS, Windows. No cgo.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-24 17:49:11 +00:00
cmd/klipdev add(cmd): clearafter in klipdev 2026-09-22 10:22:16 +05:30
internal chore(cleanup): use more concrete and exhausting checks and handling 2026-09-22 00:42:11 +05:30
go.mod Klip It 2026-09-20 17:25:47 +05:30
go.sum Klip It 2026-09-20 17:25:47 +05:30
klip.go chore(cleanup): use more concrete and exhausting checks and handling 2026-09-22 00:42:11 +05:30
klip_darwin.go Klip It 2026-09-20 17:25:47 +05:30
klip_linux.go Klip It 2026-09-20 17:25:47 +05:30
klip_windows.go chore(cleanup): use more concrete and exhausting checks and handling 2026-09-22 00:42:11 +05:30
README.md Update README.md 2026-09-24 17:49:11 +00:00

klip

Native clipboard access for Go — Linux (Wayland/X11), macOS, Windows.

Built to actually solve the "copied a password, program exited, clipboard went blank" problem you get on Wayland with most clipboard libraries: on Linux, klip shells out to wl-copy/xclip/xsel, which fork and keep serving the clipboard after your process exits. On macOS it uses pbcopy/osascript; on Windows it talks to the Win32 clipboard API directly. No cgo.

Install

go get plutolab.org/klip

Usage

cb := klip.NewClipboard()

// plain copy
cb.Write(ctx, []byte("hello"), klip.WriteOptions{})

// copy a secret: hint clipboard managers to keep it out of history,
// and clear it after the first paste where supported
cb.Write(ctx, []byte(password), klip.WriteOptions{
	Secret:       true,
	ClearOnPaste: true,
})

// clear now, but only if the clipboard still holds what we wrote
cb.Clear(klip.DirectCompare([]byte(password)))

// clear unconditionally
cb.Clear(klip.Always)

Options

WriteOptions field Linux macOS Windows
Secret (hide from clipboard history) wl-copy --sensitive; no-op on xclip/xsel org.nspasteboard.ConcealedType/TransientType ExcludeClipboardContentFromMonitorProcessing
ClearOnPaste wl-copy --paste-once / xclip -loops 1; no-op on xsel not supported not supported

ClearOnPaste/paste-once only exists where the OS lets a process serve its own clipboard selection on request (Wayland, X11). macOS and Windows hand clipboard content to the OS immediately, with no way to observe a paste, so there's nothing to hook there.

Clearing on a timeout

klip has no background timer of its own — a library can't safely spawn one that outlives your process without doing something surprising to every program that imports it. Instead:

  • Clear(cmp ClearComparator) error / ClearAfter(cmp ClearComparator, d time.Duration) error — verify-then-clear, and sleep-then-verify-then-clear. Call these from your own worker process.
  • klip.LaunchDetached(exePath, args, payload) error — spawns that worker as a real detached process (survives your program exiting), delivering payload via stdin.

Your app registers its own worker entry point (a hidden subcommand, same idea as gopass unclip), calls LaunchDetached right after Write, and has that worker call ClearAfter.

Known gaps

  • Linux: KDE's Klipper re-asserts old content after a plain clear. A fix exists (clearKlipperHistory in internal/clipboard_linux.go) but isn't wired in yet — it works by wiping Klipper's entire history, not just the one entry, which isn't always the right tradeoff.
  • macOS/Windows: unverified beyond compiling — no Mac/Windows machine in the loop yet. verified now.