clippy
A clipboard manager for the terminal. It watches your clipboard, keeps a searchable history of everything you copy, and lets you re-copy, favorite, edit, or export old items. No dependencies, just the standard library. Works on macOS, Linux, and Windows.
Install
The quickest way to get a clippy command that works from any directory:
./install.sh
This copies the app into ~/.local/lib/clippy and puts a clippy launcher in
~/.local/bin. If ~/.local/bin isn't on your PATH yet, add it:
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.zshrc
As a Python package
Installable as a normal package, either from source or from PyPI once published:
pip install . # from the repo
pipx install . # isolated, via pipx
pip install clippy-clipboard # from PyPI (name on PyPI is clippy-clipboard)
Using it as a library:
from clippy import ClipboardManager, add, search, stats, top
add("hello world")
print(search("hello"))
Other install options
./install.sh --pip # install via pip into a private venv
./install.sh --system # install into /usr/local/bin (run with sudo)
./install.sh --uninstall # remove everything it installed
You can also skip installing and run from the repo:
python -m clippy
Where your history lives
History is stored in one global file, ~/.clippy_history.json, so it's the same no
matter which directory you're in. If you had an older data.json lying around, it gets
copied over automatically the first time you run clippy.
You can point clippy at a different file with the CLIPPY_DATA environment variable —
handy for testing:
CLIPPY_DATA=/tmp/try.json clippy watch
Each entry keeps the text, a timestamp, how many times it was copied, and an optional favorite flag. History is capped at 500 items, dropping the oldest when new copies come in.
Using it
Run clippy with no arguments to open the interactive menu. Everything you copy while
it's open gets added automatically.
clippy
To just log copies to the terminal instead of the menu:
clippy watch
Commands
| Command | What it does |
|---|---|
menu |
Interactive menu (this is the default) |
watch |
Watch the clipboard and log new copies |
history |
List everything you've saved |
search <query> |
Search your saved text |
top [n] |
Most-copied items, top 10 by default |
stats |
Some aggregate stats |
favorite <index> |
Toggle the favorite flag on an item |
edit <index> |
Open an item in your $EDITOR |
delete <range> |
Delete by index, e.g. 3, 3-10, 1,3,7, or all |
truncate <n> |
Keep only the first n items |
dedupe |
Remove duplicate entries |
backup |
Copy the data file with a timestamp |
export [json|txt|md] [file] |
Write history out to a file |
import <file.json> |
Merge entries in from a JSON file |
gui |
A small windowed app, if you have tkinter |
get <index> |
Print an item's text (1 = most recent). Great for scripts |
set <text> |
Add an item to history and copy it to the clipboard |
api <path> |
Call the running server's REST API (see below) |
serve |
Host a local web page + REST API on localhost |
Every read/write command prints an exit code of 0 on success, and most accept a --json
flag that emits machine-parseable JSON instead of human text. Combine this with the global
CLIPPY_DATA env var and clippy becomes scriptable:
clippy history --json # full history as JSON
clippy search "deploy" --json # matching items as JSON
clippy stats --json # aggregate stats as JSON
clippy get 1 # just the most recent item's text
clippy get 3 --json # the 4th item's full record
CLIPPY_DATA=/tmp/project.json clippy set "$(pwd)" # capture cwd
For get, set, and api, pass --json to force JSON output. For the other commands
--json switches their output to JSON.
Menu keys
j/k or arrows move up/down
f/b or PgUp/Dn page
g / G jump to top / bottom
enter copy the selected item
/ search (Enter to search, n for next match)
e edit in $EDITOR
f toggle favorite
F only show favorites
d delete the selected item
c clear the whole history
q quit
GUI
clippy gui opens a frameless, draggable window with a live-updating list, a search
box, and a range-delete field (try 3-10 or all). Double-click an item to copy it.
It needs a Python built with tkinter:
- macOS:
brew install python-tk@3.14 - Debian/Ubuntu:
sudo apt install python3-tk
If you installed with pipx and clippy gui complains about tkinter, reinstall using a
Python that has it:
pipx install --python /usr/bin/python3 .
Local server & REST API
clippy serve starts a small local HTTP server so another program — a script, a browser, a
widget, an editor plugin — can read and drive clippy over HTTP. It has zero dependencies
(built on Python's standard library) and binds to 127.0.0.1 only, so nothing is exposed
to the network.
clippy serve # picks a free port, prints the URL
clippy serve --port 8765 # run on a specific port
clippy serve --host 0.0.0.0 # listen on all interfaces (be careful!)
On startup it prints the web dashboard URL, plus three things aimed at developers:
http://127.0.0.1:<port>/api/docs— human-readable API referencehttp://127.0.0.1:<port>/api/openapi.json— machine-readable OpenAPI 3.0 spechttp://127.0.0.1:<port>/api/health— liveness probe for uptime checks
Visit the printed URL in a browser to get a small dashboard where you can read the current clipboard, set it, save items, search, and manage history.
Developer / API endpoints
All endpoints return JSON and accept cross-origin requests, so browser widgets and other
tools can use them directly. The openapi.json spec describes the whole surface for
codegen, API clients, and editors.
| Method | Path | What it does |
|---|---|---|
GET |
/ |
The web dashboard |
GET |
/api/status |
Server status, version, item count, current clipboard |
GET |
/api/health |
Liveness probe — {"status":"ok"} |
GET |
/api/docs |
Human-readable API reference page |
GET |
/api/openapi.json |
Machine-readable OpenAPI 3.0 spec |
GET |
/api/clipboard |
Current clipboard text ({"clipboard": "..."}) |
POST |
/api/clipboard |
Set the clipboard. Body: {"text": "..."} |
GET |
/api/history |
Full history ({"items": [{"index", "text", ...}]}) |
POST |
/api/history |
Add an item. Body: {"text": "..."} |
DELETE |
/api/history |
Clear all history |
GET |
/api/history/<i> |
One item |
PUT |
/api/history/<i> |
Update one item. Body: {"text": "..."} |
DELETE |
/api/history/<i> |
Delete one item |
POST |
/api/history/<i>/favorite |
Toggle favorite |
POST |
/api/history/<i>/copy |
Copy the item to the clipboard |
GET |
/api/search?q=<query> |
Search history |
GET |
/api/top?n=<count> |
Most-copied items |
GET |
/api/stats |
Aggregate stats |
GET |
/api/favorites |
Favorite items |
GET |
/api/count |
Number of saved items |
GET |
/api/backup |
Create a timestamped backup file |
GET |
/api/export?format=json|txt|md |
Export history |
From another program, this makes clippy a small self-hosted clipboard service. For example, from any language with HTTP:
curl -s http://127.0.0.1:8765/api/health
curl -s http://127.0.0.1:8765/api/history
curl -s -X POST http://127.0.0.1:8765/api/history -H 'Content-Type: application/json' -d '{"text":"pasted via curl"}'
curl -s -X POST http://127.0.0.1:8765/api/clipboard -H 'Content-Type: application/json' -d '{"text":"new clipboard"}'
Handy without a dedicated HTTP client, the api command shells out to the running server:
clippy api /api/history # GET, prints pretty JSON
clippy api /api/search?q=deploy
clippy api /api/health # liveness probe
clippy api /api/openapi.json # machine-readable OpenAPI spec
clippy api /api/docs --json=false # fetch the reference page as raw HTML
clippy api /api/history --method POST --data '{"text":"hello from a script"}'
clippy api /api/clipboard --method POST --data '{"text":"new clipboard value"}'
clippy api /api/history/3 --method DELETE
clippy api / --json=false # vanilla output, no pretty-print
api talks to 127.0.0.1:8765 by default; point it elsewhere with --port.
Development
clippy/ the package
core.py history storage and helpers
clipboard.py cross-platform clipboard access
server.py local HTTP server, REST API, and web page
cli.py command-line interface, TUI, and GUI
Run the tests:
python -m pytest
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clippy_clipboard-2.3.tar.gz.
File metadata
- Download URL: clippy_clipboard-2.3.tar.gz
- Upload date:
- Size: 43.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b07d7132cbea513bccb5c1b6d18b8ae5c5d2b3e11f4fe424441694c3d0c1702
|
|
| MD5 |
879f4b89f10bc4e3e6cfd67c323b6a56
|
|
| BLAKE2b-256 |
e5f0f00a9f4f14a524b0940f014466b6c76be0c31cf15d27cd6441cf8b2d35f9
|
File details
Details for the file clippy_clipboard-2.3-py3-none-any.whl.
File metadata
- Download URL: clippy_clipboard-2.3-py3-none-any.whl
- Upload date:
- Size: 41.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96a057cae9cccafe16874331fe22495c45c897a373dbfc88011674ff20c1fb7b
|
|
| MD5 |
724e0acff0a9501319d037e286bfd6be
|
|
| BLAKE2b-256 |
245068179cd7dd2f5f0bc8635379cad0ab94362c33b896e410ad7ea2314b7854
|