beamboard — pasteboard sync
Self-hosted clipboard sync for devices on a Tailnet (or any private network).
Three small programs (the two Python ones ship as one package, beamboard),
one tiny HTTP+JSON protocol:
macOS app ──┐ ┌── TrueNAS docker-compose
(menubar, ├── HTTP over Tailnet ─┤ pbd + SQLite
pasteboard │ └── history capped at N clips
sync) │
pb CLI ───┘ (copy / paste / history / watch)
The server is the single source of truth; every clip gets a monotonically
increasing seq. Clients are stateless and reconcile against seq.
Everything is plain text, stdlib-only Python, and dependency-free Swift.
Server (TrueNAS / docker-compose)
cd server
docker compose up -d --build
Point the volume in docker-compose.yml at a dataset
(e.g. /mnt/tank/apps/pb:/data, writable by uid 1000) for persistent history.
Or run it anywhere with Python: pipx install beamboard (from a checkout:
pipx install .), then PB_DATA=./data pbd (alias: pb serve). No dependencies.
| Env | Default | |
|---|---|---|
PB_PORT |
8737 |
listen port |
PB_DATA |
~/.local/share/pb (/data in Docker) |
directory for pb.db |
PB_TOKEN |
(unset) | optional shared bearer token; unset = no auth (trust the Tailnet) |
PB_HISTORY |
100 |
clips to keep |
PB_MAX_BYTES |
1048576 |
max clip size |
CLI client (Linux or anywhere)
pipx install beamboard # from a checkout: pipx install . (or: make install)
pb config url http://truenas:8737 # saved to ~/.config/pb/config.json
# pb config token ... # if the server sets PB_TOKEN
echo "text" | pb copy # copy to the shared pasteboard
pb paste > file.txt # paste from it (byte-verbatim)
pb history [n] [--json] # recent clips
pb watch # print each new clip as it arrives (pipeable)
The same stdlib-only package (beamboard) provides the pbd server and the
pb command, also installed as beamboard (beamboard/server.py and cli.py).
pb copy/pb paste behave like macOS pbcopy/pbpaste; a symlink or alias
named pbcopy/pbpaste pointing at pb restores the old spelling.
pb config shows the effective settings; PB_URL, PB_TOKEN and PB_DEVICE
override the config file (device defaults to the hostname). make check builds
the sdist and wheel and validates them for PyPI.
macOS menubar app
make -C mac app # builds BeamBoard.app (SwiftPM, no Xcode project)
make -C mac install # copies it to /Applications
Open BeamBoard, click the clipboard icon in the menu bar, and set the server URL (and token) in the settings. The app then:
- watches the system pasteboard (polls
changeCounttwice a second — the pasteboard has no change notifications) and pushes new local clips, - long-polls the server and writes clips from other devices into the system pasteboard,
- shows the shared history in the menu bar; clicking an entry copies it.
It never overwrites your pasteboard at launch — syncing starts with the first actual change on either side. Requires macOS 13+. The build is ad-hoc signed; add it to Login Items for autostart.
Protocol
Clip: {seq: int, ts: float, mime: "text/plain", text: str, device: str}
| Endpoint | Behavior |
|---|---|
GET /clip |
latest clip, 204 if empty |
POST /clip {text, device} |
store new head, returns {seq}; identical to current head → deduped (returns existing seq) |
GET /history?limit=50 |
recent clips, newest first |
GET /watch?since=SEQ&timeout=30 |
long-poll: latest clip once head seq > SEQ, else 204 on timeout |
GET /healthz |
200 ok (never requires auth) |
With PB_TOKEN set, all other endpoints require Authorization: Bearer <token>.
Long-polling keeps every client a dumb HTTP GET loop — no streams, no state,
self-healing across server restarts.
Echo loops are broken by three cheap layers: the server dedups identical
consecutive text, the macOS app skips pasteboard changes it caused itself,
and the device field lets clients ignore their own clips from /watch.
Security
There is no TLS and (by default) no auth: the design assumes the server is
only reachable over a trusted private network such as a Tailnet. Set
PB_TOKEN for a cheap second layer. Do not expose the port to the internet.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file beamboard-0.0.1.tar.gz.
File metadata
- Download URL: beamboard-0.0.1.tar.gz
- Upload date:
- Size: 8.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
289d54311c8cb091b3e94d8ffea6c75f646ac220c1cb866d41df5632ed7c4d34
|
|
| MD5 |
415aa8701b4f4b13ea625bc7c11e6c54
|
|
| BLAKE2b-256 |
9b77ed79d7b98cb9b0f6ee5ed1efdefd35aa467875a714e530a1f2a238a885c0
|