Self-hosted service
UniClipboard/UniClipboard avatar
UniClipboard/UniClipboard

UniClipboard: 1.0 converted your local data and cannot go back, the installer pipes a remote shell, and the root Makefile builds one crate

Real-time clipboard sync across all your devices, local-first, peer-to-peer, and end-to-end encrypted. No account. No cloud dependency. No central server.

2,036 stars101 forksRustAGPL-3.0

At a glance

What is it?
A clipboard history tool in Rust with a Tauri and React desktop shell, syncing text, images, and files between your own devices over direct connections or an encrypted relay. The interesting parts are the upgrade notice, the two ways you can install it, and the gap between the no-third-party-servers claim and the relay fallback underneath it.
Who is it for?
It fits someone who wants a searchable clipboard history across a phone and several computers without an account, and the per-device controls, the headless CLI, and the automatic backup before upgrades are the parts that make it usable rather than a toy. Three things to weigh first.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • UniClipboard/UniClipboard2,036 ★ · +655
Star history
Repository2026-07-282026-11-14
UniClipboard/UniClipboard1.4k2k

655 Stars in the last 109 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Version 1.0 converted local data and cannot go back

One callout sits above the feature list and it is the most consequential line on the page. Upgrading from the 0.19 line is a breaking change: local data is converted to a new format, you cannot downgrade to 0.19 afterwards, and every device has to run 1.0 and be paired again before syncing resumes. That is three costs in one paragraph, and the middle one is the irreversible part. Two features soften it elsewhere on the page. Local data is backed up automatically before an upgrade, and if the key the system stores is lost you can recover with the original space passphrase, which is also what the pairing flow requires. So the tool does keep an escape hatch for the key, but not for the format. A multi-device household that upgrades one machine at a time will sit in a state where the upgraded device cannot sync with the ones still on the old version.

Releases are signed, and the installer is a piped shell script

Each release publishes signature files and a signed checksum manifest, which is more than most desktop tools do.

bash
# Pin a specific version
curl -fsSL https://uniclipboard.app/install.sh | bash -s -- --version v1.0.1

The convenience path shown above it downloads a script from the project site and runs it straight from standard input.

bash
curl -fsSL https://uniclipboard.app/install.sh | bash

The script detects the operating system and processor, then picks a path: on macOS it fetches an app archive, unpacks it, and moves the bundle into the applications directory, asking for elevation if that directory is not writable, with a prefix flag available for a per-user install; on Linux it installs a deb package with elevation on apt systems, uses a COPR repository on dnf systems, uses the Snap package on Ubuntu 20.04, and otherwise drops an AppImage into a directory under your home with a desktop entry and no root at all. There is also a flag to force the AppImage path. So the two routes verify differently: downloading an artifact and checking it against the signed manifest is a different act from executing a script fetched at the moment you run it.

A relay sits underneath the no-servers claim

The pitch at the top of the page says no cloud account and no third-party servers, and that the clipboard never leaves your devices in a form anyone else can read. The sync feature says something narrower and more useful: devices connect directly on the same network or across the internet with automatic NAT traversal, and when no direct path exists they fall back to an encrypted relay, and you can add your own relay servers. Both statements can hold at once, because the guarantee the page actually makes is about readability rather than about infrastructure. A relay in the middle sees ciphertext and moves bytes. What the sentence does not settle is who operates the fallback relay when you have not configured your own, which is the question a reader of a no-servers claim is entitled to ask. The repository answers indirectly: there is a workers directory, a deploy directory, and a web server crate among the workspace members.

Eighteen workspace members and one crate kept out of the build

The root manifest describes itself as the workspace for a monorepo and spells out the layout in a comment: runnable binaries in one directory, libraries in another, and the desktop application with a React frontend plus a Tauri packaging shell and its own adapter crate. The member list runs to eighteen entries covering platform paths, observability, bootstrap, a daemon split across contract, process, local, and client crates, a web server, a desktop host, CLI macros, the CLI, the daemon, a quick panel core and app, and the GUI shell.

toml
exclude = ["tests/e2e"]

That exclusion has its own comment explaining the reason: the end-to-end test crate would otherwise drag reqwest, libc, and assert_cmd into every pull request check, so it is built explicitly by its own manifest path. The split is a deliberate answer to check cost, which tells you the test suite is large enough for that to matter. The same manifest pins the workspace version and licence at the package level, so every crate inherits them.

Workspace lints forbid unwrap and println with two exceptions

The workspace carries clippy settings that turn four patterns into warnings for every member crate.

toml
[workspace.lints.clippy]
unwrap_used = "warn"
expect_used = "warn"
print_stdout = "warn"
print_stderr = "warn"

The comment above them says these mirror a machine-checked subset of the project's own agent rules, written as no unwrap or expect in production code and use tracing rather than the print macros, and it names the exemptions: tests are allowed through a clippy configuration file, a throwaway benchmarking crate stays out, and the CLI opts out at crate level because its standard output is the product. That last exemption is the honest kind, the kind where the rule yields to the interface. The rules are warnings rather than errors, so a member crate that opts out of the workspace lints entirely, which the comment says is allowed, would compile without them.

The root Makefile builds one crate out of eighteen

The Makefile at the root of the monorepo is written with Chinese section banners and a default target that prints three lines.

make
PKG   := uc-platform

build:
	$(CARGO) build -p $(PKG)

Those three lines are build, check, and clean, and all three operate on the single platform crate the variable names. Nothing in it touches the desktop application, the daemon, the CLI, or the GUI shell, and the file predates the JavaScript side entirely: the frontend is built with a package manager and a Tauri wrapper rather than with make. So the Makefile is a leftover from an earlier, smaller layout, or a convenience for one crate that is the first thing to compile. The real build orchestration lives in the package manifest, where the desktop build first prepares sidecar binaries through a script and then invokes the Tauri build, and where a separate script assembles the mobile artifacts.

Two profiles and two modes fake a second device

The package manifest solves the hardest testing problem for a sync tool, which is having two machines, by scripting it.

json
    "tauri:dev:peerA": "cross-env UNICLIPBOARD_ENV=development UC_PROFILE=a UC_CLIPBOARD_MODE=full bun run tauri dev",
    "tauri:dev:peerB": "cross-env UNICLIPBOARD_ENV=development UC_PROFILE=b UC_CLIPBOARD_MODE=passive bun run tauri dev --config '{\"build\":{\"beforeDevCommand\":\"\"}}' --no-dev-server-wait"

One launch runs a full instance against profile A, the other runs a passive instance against profile B with the frontend dev server switched off, so a single developer can watch two devices exchange clipboard content on one machine. Two more scripts prepare the daemon sidecars, one with a debug flag. The API client is generated rather than written: one command produces an OpenAPI document from a binary inside the web server crate, and the next turns that document into the client the frontend uses, which means the two halves cannot drift apart silently.

Three alpha tags in three days above a 1.1.0 base

The release record shows three alpha builds published on three consecutive days: 1.1.0-alpha.2 on 2026-10-01, alpha.3 on 2026-10-02, and alpha.4 on 2026-10-03. Both manifests carry the same base version, 1.1.0, so the alphas sit above a stable-looking number that no stable tag carries, and the last commit on the default branch is dated 2026-09-26, a week before the first of them. Everything around the project follows the same split: an English README with a Simplified Chinese one beside it, an English and Chinese pair for both the about and contributing documents, and a user interface translated into English, two forms of Chinese, Japanese, Russian, and Brazilian Portuguese. The root also carries an about and trust page linked from the top of the README, alongside context, vision, security, and agent instruction files, a changeset configuration, and separate directories for planning, schemas, documentation site, tests, packaging, and deployment.

Editorial conclusion

It fits someone who wants a searchable clipboard history across a phone and several computers without an account, and the per-device controls, the headless CLI, and the automatic backup before upgrades are the parts that make it usable rather than a toy. Three things to weigh first. The 1.0 upgrade rewrote local data in a direction you cannot reverse, so read the migration guide and back up before you install it. The privacy claim rests on ciphertext rather than on the absence of infrastructure, since a relay carries your traffic when a direct path fails. And the install script pipes a remote file into your shell, so the signed checksums published beside each release are the path that lets you verify what you actually run.

Frequently asked questions

Can I go back to version 0.19 of UniClipboard after upgrading to 1.0?

No. The page states that 1.0 converts local data to a new format and that downgrading to 0.19 afterwards is not possible. It also says local data is backed up automatically before an upgrade, and a migration guide exists for the 0.19 to 1.0 step.

Does UniClipboard need an account or a central server?

No account is needed. Devices join a shared space with a short-lived invitation code and the space passphrase, connect directly where a path exists, and fall back to an encrypted relay when none does. You can also add your own relay servers.

How do I install UniClipboard on Linux or macOS?

Packages come as deb, rpm, and AppImage for Linux and a dmg for macOS, or you can run the install script, which detects the system, uses COPR on dnf systems and the Snap package on Ubuntu 20.04, and falls back to an AppImage under your home directory with no root. A flag forces that rootless path.

What can the uniclip command line tool do?

It handles setup, pairing, sending, receiving, and member management without a user interface, which makes it usable over SSH sessions, in scripts, and on servers. CLI-only archives are published for macOS, Linux with musl, and Windows on x86_64.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/uniclipboard-uniclipboard.svg)](https://hysenlabs.com/projects/uniclipboard-uniclipboard)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/uniclipboard-uniclipboard.svg)](https://hysenlabs.com/projects/uniclipboard-uniclipboard)

Was this useful?