Documentation
ClipSlots reference
Every command, every config option. For the 30-second pitch see clipslots.dev.
Getting started
Install #
Install via Homebrew, grant accessibility, start the daemon. Three commands, ~30 seconds.
$ brew tap olafglad/clipslots
$ brew install clipslots
$ clipslots permissions # grant accessibility (one-time)
$ clipslots start
Other install methods (.pkg download, build from source) are
listed on the
GitHub releases page.
First-time setup #
ClipSlots needs macOS accessibility permission to register global hotkeys. Without it, the daemon runs but hotkeys do nothing.
-
Run
clipslots permissions— it opens System Settings → Privacy & Security → Accessibility. -
Find
clipslotsin the list and toggle it on. -
Run
clipslots start. The daemon launches and registers your hotkeys. It will also start on login from now on. - Copy something, press Ctrl+Option+1, then press Ctrl+1 to paste it back.
Keybind syntax #
Hotkeys are configured in
~/.config/clipslots/config.toml
under [keybinds]. Each value
is a string with +-separated
modifiers and one key. Use
{n} as a placeholder for the
slot number — ClipSlots registers one hotkey per slot
(1 through your configured slots count).
| Modifiers | Keys | Placeholder |
|---|---|---|
ctrl, option, cmd, shift |
0-9, a-z, f1-f12 |
{n} = slot number |
Examples:
# Default: Ctrl+Option+N to save, Ctrl+N to paste
save = "ctrl+option+{n}"
paste = "ctrl+{n}"
# Cmd+Shift+N to save, F-keys to paste
save = "cmd+shift+{n}"
paste = "f{n}"
Config changes hot-reload — no restart needed. If a binding conflicts with another app, the daemon logs a warning and skips that slot.
Daemon
start#
Start the ClipSlots daemon and install a launchd agent so it boots on login.
$ clipslots start
stop#
Stop the daemon and unload the launchd agent. Hotkeys go inert until you start again.
$ clipslots stop
restart#
Stop the daemon, then start it again. Useful after a manual binary swap. Most config changes hot-reload, so you rarely need this.
$ clipslots restart
status#
Show daemon state, accessibility permission, slot usage, and active keybinds. In a wide colour TTY it renders a fastfetch-style layout with the ClipSlots ASCII logo; piped output or
NO_COLOR=1 falls back to plain stacked sections.
$ clipslots status
permissions#
Check accessibility and pasteboard permission state, and open System Settings → Privacy & Security if accessibility is not granted yet. Idempotent — safe to run any time.
$ clipslots permissions
Slots
save#
Save the current clipboard contents into a slot. Works with text, images, RTF, HTML, and file references — whatever the pasteboard holds. The equivalent of pressing your save hotkey.
$ clipslots save <slot>
$ clipslots save 3
$ echo "hi" | pbcopy && clipslots save 5
Refuses to overwrite locked slots. Saving an empty clipboard is a no-op.
paste#
Load a slot's content back onto the system clipboard. The equivalent of pressing your paste hotkey.
$ clipslots paste <slot>
$ clipslots paste 3
peek#
Print a slot's text content to stdout without touching the clipboard. Useful for shell scripting and quick inspection. Non-text slots (images, files) print a short type description instead of binary data.
$ clipslots peek <slot> [--truncate <N>]
$ clipslots peek 3
$ TOKEN=$(clipslots peek 7)
$ diff <(clipslots peek 1) <(clipslots peek 2)
| Flag | Description |
|---|---|
--truncate N | Truncate output to N characters (no truncation by default). |
list#
Show every slot with a content preview, age, and (when colour
is on) a lock indicator. Use
--verbose for size and type
metadata, or --grep to filter.
$ clipslots list [--grep <pattern>] [--verbose]
$ clipslots list
$ clipslots list --verbose
$ clipslots list --grep token
| Flag | Description |
|---|---|
--grep PATTERN | Filter slots whose label or preview contains the pattern (case-insensitive). |
-v, --verbose | Show per-slot size, type, age, label, and lock state. |
open#
Open a slot in the appropriate application based on its
content type — text in $EDITOR,
files in their default app, images in Preview, rich text in TextEdit.
$ clipslots open <slot>
$ clipslots open 3
clear#
Clear a single slot or every slot. Locked slots are protected
by default — use --force to
wipe them too, or --keep-locked
to skip them non-interactively.
$ clipslots clear [<slot>] [--force] [--keep-locked]
$ clipslots clear 3
$ clipslots clear 3 --force
$ clipslots clear --keep-locked
| Flag | Description |
|---|---|
<slot> | Optional. Omit to target every slot. |
--force | Clear every slot, including locked ones. Non-interactive. |
--keep-locked | Clear only unlocked slots. Non-interactive. |
Organize
label#
Attach a human-readable label to a slot so you can spot it in
list output. Labels persist
across writes and survive the manifest cache being rebuilt.
$ clipslots label <slot> [<name>] [--clear]
$ clipslots label 3 "API token"
$ clipslots label 3 --clear
lock#
Lock a slot so save,
clear, and
undo refuse to touch it.
Useful for slots holding tokens or boilerplate you don't
want to overwrite by accident.
$ clipslots lock <slot>
$ clipslots lock 3
unlock#
Unlock a slot so it can be overwritten again.
$ clipslots unlock <slot>
$ clipslots unlock 3
swap#
Exchange the contents of two slots. Labels and lock state move with the content.
$ clipslots swap <a> <b>
$ clipslots swap 1 4
copy#
Duplicate the contents of one slot into another, overwriting the destination (unless it is locked).
$ clipslots copy <src> <dst>
$ clipslots copy 1 4
undo#
Swap a slot with its prior content. Each slot keeps one undo
snapshot, taken at the moment of its last write — running
undo twice round-trips back
to the current value. Locked slots are protected.
$ clipslots undo <slot>
$ clipslots undo 3
Backup
export#
Bundle all slots, labels, and locks into a single tar archive — for backup, machine migration, or sharing a snapshot of your boilerplate.
$ clipslots export <path>
$ clipslots export ~/clipslots-backup.tar
import#
Restore slots from a tar archive previously created by
export. By default,
non-empty slots in the destination are preserved — pass
--force to overwrite them.
$ clipslots import <path> [--force]
$ clipslots export ~/clipslots-backup.tar
$ clipslots import ~/clipslots-backup.tar --force
| Flag | Description |
|---|---|
--force | Overwrite existing non-empty slots. |
Config
config#
Print the current configuration: config-file path, general settings, and active keybinds. Reads the same file the daemon does.
$ clipslots config
config edit#
Open ~/.config/clipslots/config.toml in
$EDITOR (or
nano if unset). The daemon
hot-reloads on save — no restart needed.
$ clipslots config edit
config validate#
Parse and validate the config file. Exits non-zero with a specific error and file path on stderr if something is wrong — handy in shell scripts or pre-commit hooks for a synced dotfiles repo.
$ clipslots config validate
config path#
Print the absolute path to the config file. Composes nicely with other tools.
$ clipslots config path
$ vim $(clipslots config path)
Configuration
config.toml schema #
ClipSlots reads ~/.config/clipslots/config.toml.
Every option is optional — omit any line and ClipSlots uses
a sensible default. The daemon hot-reloads on save.
# Number of slots (1-10)
slots = 5
# Show daemon logs in terminal (true/false)
verbose = true
# Optional: auto-expire stale slots after this many hours.
# Locked slots are never expired. Omit to disable.
# expire_after_hours = 24
# Optional: play a system sound on successful hotkey actions.
# Valid values: "off", "sound". CLI commands never play sound.
# feedback = "sound"
[keybinds]
save = "ctrl+option+{n}"
paste = "ctrl+{n}"
# Optional: append-mode hotkey. See "Append mode" below.
# append = "ctrl+option+shift+{n}"
# append_separator = "\n"
| Key | Type | Default | Description |
|---|---|---|---|
slots |
int | 5 |
How many slots to register hotkeys for. 1–10. |
verbose |
bool | true |
Write save/paste actions and errors to /tmp/clipslots.log. |
expire_after_hours |
int | off | Auto-clear slots untouched for N hours. Locked slots are never expired. |
feedback |
string | "off" |
Play a system sound on successful hotkey actions. "off" or "sound". |
keybinds.save |
string | "ctrl+option+{n}" |
Hotkey to save the clipboard into slot N. |
keybinds.paste |
string | "ctrl+{n}" |
Hotkey to paste slot N back onto the clipboard. |
keybinds.append |
string | off | Optional hotkey to append clipboard text to a slot. See Append mode. |
keybinds.append_separator |
string | "\n" |
Separator inserted between existing content and the appended text. |
Append mode#
Append mode is an optional third hotkey that adds clipboard
text to an existing slot instead of overwriting it — handy
for collecting snippets while you read or research. Disabled
by default. Uncomment the two lines under
[keybinds] to enable.
[keybinds]
save = "ctrl+option+{n}"
paste = "ctrl+{n}"
append = "ctrl+option+shift+{n}"
append_separator = "\n"
Appending to an empty slot acts as a normal save. Appending to a locked slot, or appending non-text clipboard content, is silently skipped. Rich-text slots collapse to plain text on append.
Slot expiry#
Set expire_after_hours to
automatically clear stale slots. The daemon sweeps once per
hour and clears any slot whose last write is older than the
threshold. Locked slots are never expired.
# Clear slots untouched for more than 24h
expire_after_hours = 24
Sound feedback#
When feedback = "sound", the
daemon plays a short system sound on successful save, paste,
or append from a hotkey. CLI commands
(clipslots save 3 etc.) never
play sound — only hotkeys do.
feedback = "sound"
Reference
Troubleshooting#
Hotkeys do nothing after install
Almost always missing accessibility permission. Run
clipslots permissions,
toggle clipslots on in
System Settings, then
clipslots restart.
Accessibility permission doesn't stick after rebuild
macOS ties accessibility to the binary's code signature.
Unsigned (or differently-signed) builds register as a new
app and lose permission. The Homebrew and .pkg distributions are signed consistently and don't have this issue.
Daemon won't start
Check /tmp/clipslots.err for the actual error. Common causes: another process bound a hotkey first (the daemon logs which one), or the config file has a syntax error (clipslots config validate will say so).
A specific hotkey doesn't fire
Some macOS shortcuts (Ctrl+Space, Cmd+Tab) and third-party tools like Raycast, Alfred, or Karabiner can claim a binding before ClipSlots gets it. Try a different combo (see the keybind syntax) or check the offending app's hotkey settings.
Saved an image but pasting gives garbled text
Some apps only accept the clipboard type they expect. ClipSlots restores the original pasteboard types faithfully — if the destination app only reads text, an image won't show. Try pasting into Preview or Finder to confirm the slot does contain an image.
How do I uninstall?
clipslots stop to unload the daemon, then brew uninstall clipslots. Slot data lives at ~/.local/share/clipslots/ and config at ~/.config/clipslots/ — delete those too for a full wipe.
File paths#
| Path | What |
|---|---|
~/.config/clipslots/config.toml | Configuration file. |
~/.local/share/clipslots/slots/ | Slot contents, labels, locks. |
~/Library/LaunchAgents/com.clipslots.daemon.plist | launchd agent that boots the daemon on login. |
/tmp/clipslots.log | Daemon stdout (when verbose = true). |
/tmp/clipslots.err | Daemon stderr — check here when something breaks. |