UniClipboard

CLI Reference

Public uniclip commands for spaces, members, content, search, diagnostics, and mobile sync.

Edit on GitHub

This page covers the commands included in release builds and shown by uniclip --help. New to the CLI? Start with Getting started. Development-only and hidden commands are documented in the repository, not in the user guide.

Daemon lifecycle

Use run and service for lifecycle control; Getting started lists their commands. run keeps the daemon in the foreground and refuses an existing daemon. It can run before space setup; initialize or join from another terminal. start retains its old background default during deprecation.

service manages only its own profile-scoped user service, without sudo. macOS requires a GUI login domain; Linux requires a running user systemd manager. service start is idempotent. To change options on a running service, stop it first and start with the desired options. restart uses saved options. There is no automatic crash-restart policy.

service status --json reports installed, loaded, running, pid, http_health and optional health_details. A running PID does not prove health. A stopped service, unreachable or incompatible HTTP endpoint, or an endpoint owned by another daemon returns nonzero. recovery_required means the daemon is reachable but recovery is still required. start and restart wait for HTTP health and return nonzero on failure, leaving the service available for diagnosis.

The service preserves the selected profile, HOME and data/log context; it does not persist passwords or daemon tokens. The login keychain may still be locked. macOS console logs are service.stdout.log and service.stderr.log in the profile log directory; Linux uses journalctl --user -u <name>.service, with name from status. Daemon rotating logs continue unchanged.

To remove a definition, run service stop, then remove its named plist from ~/Library/LaunchAgents or unit from $XDG_CONFIG_HOME/systemd/user (default ~/.config/systemd/user). On Linux, run systemctl --user daemon-reload after removal. The CLI does not configure Linux linger for startup before login.

Space

CommandEffect
uniclip space statusShow the current space and device-trust summary.
uniclip space initCreate a new encrypted space for this profile.
uniclip space inviteIssue a one-time pairing invitation.
uniclip space joinEnter an invitation interactively, or pass --code <CODE>; add --switch to move to a different space.
uniclip space reset --yesRebuild as a new one-device space while retaining local history, completed files, settings, and device access.
uniclip space change-passphraseChange the space passphrase of an unlocked, single-device space while keeping local history.

Space reset permanently discards old pairing, trust, and sync relationships. Every device must pair again. It does not erase local history and is not a factory reset. It keeps the current passphrase.

uniclip space change-passphrase prompts for the new passphrase twice (or takes --passphrase <PASSPHRASE>; required with --json). It does not ask for the current passphrase. It is only accepted while this device is the only member of the space and the space is unlocked, and it invalidates unused pairing invitations. uniclip space init cannot be used for this: it only works on a device that has no space yet.

For scripts, uniclip --json space init --passphrase <PASSPHRASE> returns one JSON object containing space_id, device_id, and fingerprint. The passphrase is required because JSON mode never opens an interactive prompt. uniclip --json space invite streams newline-delimited JSON: the first event contains the invitation code and expiry, and a later event reports completion, failure, or interruption. This lets a caller read the invitation before the command finishes waiting for the other device.

space join waits for the final result by default. --no-wait returns after the request is accepted; space join status and space join cancel inspect or cancel that pending request. A space switch asks for confirmation unless --yes is supplied. During a switch, --preserve-unreadable-history keeps local records that cannot be read instead of dropping them.

Join requests

CommandEffect
uniclip space join --no-waitRecord a pending join and return without waiting for its final result.
uniclip space join statusShow the current join request and its Engine-owned status.
uniclip space join cancelRequest cancellation of the current pending join.

Ctrl-C stops only the local wait; use space join cancel when the request itself should be cancelled.

Members

CommandWhat it shows
uniclip member listThis space's members — the local device plus paired peers — with each peer's last-known reachability: {name} ({online | offline | unknown}).
uniclip member list --probeSame, but actively pings every paired peer first so the states are fresh (adds a network round-trip).

The former uniclip members command and its uniclip devices alias are hidden and deprecated. They still run for compatibility, but print a warning. New scripts should use uniclip member list. All three forms honour --json.

Remove a member

uniclip member remove <PEER-ID>

Removal records an irreversible intent even when that device is offline and immediately stops new content from being sent to it. Use uniclip member trust status to inspect the current relationship state after the removal.

Device trust changes

CommandEffect
uniclip member trust statusShow device names, shortened device IDs, removal proposals, and the device impact of each choice.
uniclip member trust chooseResolve device-group issues by numbered option, or submit one choice using opaque IDs.

In an interactive terminal, omit --issue and --choice to select options by number, starting at 1. Invalid numbers show the valid range and let you retry without submitting any choice. After a completed or already-completed choice, the command reads the latest state and continues through the remaining issues by default. Add --once to handle only one issue. Pending changes, required re-pairing, changed state, or required local-removal confirmation stop the workflow. A choice that removes this device also ends the call.

Interactive local removal requires explicit confirmation. --confirm-local-removal authorizes only the first issue in the call; it does not authorize later issues. The command checks local-removal risk again for every issue.

Explicit IDs, non-terminal calls, and JSON calls are non-interactive and execute once. Scripts should pass --issue <ISSUE-ID> and --choice <CHOICE-ID> using opaque IDs returned by member trust status --json, rather than interactive option numbers. Removing this device also requires --confirm-local-removal. Query again if state has changed; a submitted choice may still be pending or require re-pairing.

Per-member sync

CommandEffect
uniclip member sync show <DEVICE>Show send, receive, and content-type preferences for one member.
uniclip member sync set <DEVICE> [OPTIONS]Change only the preferences explicitly supplied on the command line.

<DEVICE> can be a device ID, or an unambiguous device name in an interactive terminal. set accepts --send on|off, --receive on|off, and comma-separated --send-types / --receive-types values; use all or none for every type or no types.

Sending and watching

# Send text to every online paired device
uniclip send "hello from the CLI"

# Or pipe stdin
echo "from a heredoc" | uniclip send

# Restrict fan-out to specific devices (repeatable)
uniclip send "scoped message" --peer DEVICE_ID_A --peer DEVICE_ID_B

# Send an existing regular file (auto-detected)
uniclip send ./report.pdf

# Force an existing filename to be sent as text
uniclip send --text report.pdf

# Re-fan-out a previously captured local entry. No stdin / positional
# text is read. Without `--peer`, targets default to the diff of
# trusted peers minus those that already received this entry.
uniclip send --resend <ENTRY_ID>

# Watch inbound clipboard payloads as they arrive (Ctrl-C to stop)
uniclip watch

--resend only re-fans-out entries that were captured locally and whose payload is still cached. Entries originating on a remote peer cannot be re-sent from this device; combine --resend with --peer ... to force a specific fan-out target.

uniclip watch is a diagnostic observer: it prints the first text representation (or a per-rep summary for image-only payloads) but does not write the system clipboard — that's the daemon's job.

Sending and receiving files

# Sender: explicitly force file mode (kept for compatibility)
uniclip send -f ./big-file.bin

# Sender: read complete file paths from stdin, one per line
printf '%s\n' ./one.bin './files/two words.bin' | uniclip send -f

# Receiver: wait for the next inbound entry. Files are exported from
# the daemon's cache into the selected directory. Ctrl-C stops waiting.
uniclip get --wait --out ./inbox

An existing positional regular file is detected automatically. Use --text to force a filename to be sent as text, or -f / --file to force file mode. Without a positional path, file mode reads one complete path per stdin line; stdin contains paths, not file contents. Blank lines are ignored, all paths are validated before sending, and duplicate paths are sent once. Directories are not supported, and an explicit-looking missing path is reported as an error instead of being sent as text. File mode supports repeatable --peer; the command exits after every relevant target is delivered, failed, or offline. Ctrl-C cancels the wait. A successful get --wait uses the normal get output contract described below.

Reading already-synced entries

By default, get reads what is already in daemon history and returns immediately. Add --wait to subscribe for the next matching entry that arrives after subscription, handle it with the same output rules, and exit. --wait can be combined with --type or --id; it never consumes an older history entry or an already-finished transfer.

# Newest usable entry (text/link prints to stdout)
uniclip get

# Also copy the result to the computer where this terminal is open
uniclip get -c

# Wait for one new synced entry
uniclip get -w

# Wait for the next file and show receive progress on interactive stderr
uniclip get -w --type file

# Wait for this id only if it arrives after the command subscribes
uniclip get -w --id <ENTRY_ID>

# Wait for one new entry and copy it
uniclip get --copy --wait

# Newest entry of a kind: image | file | text | link
uniclip get --type image

# A specific entry by id (from `uniclip search`), into a directory
uniclip get --id <ENTRY_ID> --out ./inbox

# Browse recent entries instead of materializing one
uniclip get --list -n 20

Output contract: text / link content is printed to stdout (pipe-friendly). A trailing newline is appended only when stdout is an interactive terminal, so piped or redirected output stays byte-exact; image / file bytes are written to --out (a directory, defaulting to a per-user cache dir) and the absolute path is printed to stdout, or streamed to stdout with --out -. A successful fetch prints no additional status lines, so the result can be piped or captured directly. Waiting messages are written to stderr and do not corrupt stdout.

With -c or --copy, text and links copy their content; images and files copy the absolute path written to disk. For images and files, --copy cannot be combined with --out -, because streaming the bytes does not produce a path.

While waiting for a matched file, an interactive terminal shows real received bytes, total bytes and percentage when the total is known, or received bytes plus an activity indicator when it is unknown. Progress is written only to stderr; JSON stdout contains only the final result, and non-interactive stderr does not contain animation control sequences. The current pending event can prove file from a non-empty filename list, but cannot reliably distinguish image, text, or link, so those filters wait for final classification instead of locking an unrelated transfer for early progress.

The old uniclip recv [--out DIR] command is hidden and deprecated. Existing scripts still work in this release and receive one warning on stderr, but new scripts should use uniclip get --wait [--out DIR].

uniclip search exposes the encrypted full-text index that backs the GUI dashboard search.

uniclip search status                    # is the index ready / building?
uniclip search rebuild                   # rebuild from history (synchronous)
uniclip search "report"                  # default query
uniclip search "report" \
    --type text --ext md \
    --limit 20 --detailed
uniclip search "report" \
    --from-ms 1710000000000 --to-ms 1710100000000
uniclip search "report" \
    --source-device "Laptop"             # only clips from that device
uniclip search "report" \
    --operator or --time-preset last_7d \
    --tag favorited --offset 20

Filters can be combined. --type, --tag, --ext, and --source-device are repeatable. --operator selects and or or; --time-preset accepts today, yesterday, last_7d, or last_30d; --offset and --limit support pagination. A source device can be a case-insensitive name or an ID; run uniclip member list to see available names. --detailed and --json include each result's source device ID.

rebuild blocks until the rebuild finishes; useful when scripting a diagnostic snapshot.

Mobile sync

uniclip mobile ... is the CLI surface for the mobile companion feature. It mirrors the Devices → Mobile sync panel in the GUI and the protocol is documented in the Mobile LAN API.

# One-shot wizard: turn the feature on, configure the LAN listener,
# register one iPhone, print the install QR + a one-time password.
uniclip mobile setup

# Read-only view (allowed while the daemon is running)
uniclip mobile status            # combined: feature + LAN + paired devices

# Paired device management
uniclip mobile add --label "My iPhone" \
    [--username my_user] [--password-stdin]
uniclip mobile revoke <device-id>

# Advanced listener configuration. `setup` already covers the common case;
# use these to change the address or add a reverse proxy.
uniclip mobile network interfaces
# LAN form: advertise an internal IPv4 → install URL is http://<IP>:<port>
uniclip mobile network set --ip <LAN_IPV4> [--port 42720] --accept-network-risk
# Reverse-proxy form: advertise a full base URL → install URL/QR points at
# the HTTPS front-end (e.g. Caddy), while the listener stays plain HTTP.
uniclip mobile network set --url https://clip.example.com --accept-network-risk
uniclip mobile network off       # stop just the LAN listener

# Disable the feature entirely (master switch + listener off; paired
# device records stay until you `revoke` them).
uniclip mobile disable

Behavioural notes:

  • Public mobile commands use the daemon. They connect to the running service or start it when needed, so you do not need to stop the desktop app before running setup, add, or network set.
  • --json implies non-interactive. No prompts will be shown. setup in non-interactive / JSON mode requires --label and --accept-network-risk. --ip / --port are optional advanced pins (omit them and the QR carries every detected interface). --username / --password-stdin remain optional and default to auto-mint.
  • --password-stdin reads exactly one line from stdin. Use it to pipe a password from a manager / CI without leaving it in shell history.
  • Default port is 42720 (SPEC §3.2). The daemon socket always binds to 0.0.0.0:<port>; --ip only chooses the IPv4 that is printed to the install URL.
  • network set requires exactly one of --ip <IP> or --url <URL>. --ip produces the LAN form http://<IP>:<port>. --url embeds a full base URL (scheme + host + optional port) such as https://clip.example.com, so the install URL / QR points at a TLS reverse proxy (Caddy, nginx, …) while the listener itself stays plain HTTP on the internal network. The two are mutually exclusive and setting one clears the other; mobile status reflects whichever is active.

For a step-by-step setup walkthrough — listener risks, iOS Shortcut install, password rotation — see the Mobile sync guide.

Debug & log export

uniclip debug status                       # is persistent debug logging on?
uniclip debug on                           # enable verbose local logging
uniclip debug off                          # back to the normal profile
uniclip debug capture status               # inspect a connection capture
uniclip debug capture start                # start a bounded detailed capture
uniclip debug capture stop                 # stop the active capture
uniclip debug export-logs                  # zip the last 24h to Downloads
uniclip debug export-logs --since-hours 6  # narrow the window

debug on / off persists a more verbose logging profile across restarts; status reports the effective profile and whether a restart is still required for the change to fully take effect. Clipboard content is still not logged.

export-logs collects the GUI, daemon, and CLI logs from the recent window (default 24h) into a single zip in your Downloads folder — the fastest way to gather everything an issue report needs. The same action is available in the GUI under Settings → General.

Connection capture is intended for a short troubleshooting window. Check the active capture with debug capture status, stop it when reproduction is complete, then export the logs requested by support.

Upgrade-detection cursor

uniclip upgrade            # bare command prints status
uniclip upgrade status     # same as the bare command
uniclip upgrade ack        # advance the cursor to the current build

Inspects or advances the upgrade-detection cursor — exposed for manual verification of the upgrade module. Most users never need this.

Exit codes

uniclip uses stable exit codes (defined in the source under src/exit_codes.rs). 0 is success; non-zero values map to distinct failure classes (configuration, network, pairing, etc.) and are stable across releases. Scripts should branch on exit code rather than parse human-readable output.

uniclip get additionally uses 6 when no entry matched the selector, and 7 when an entry matched but its payload is unavailable (Lost or not yet downloaded — re-send it from the source device).

For the most up-to-date list of subcommands, run uniclip --help — the binary's help is the source of truth.

On this page