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.
Metadata
Release files for beamboard 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| beamboard-0.0.1.tar.gz | 8.4 kB | Without provenance | Details |
Release files / beamboard-0.0.1.tar.gz
| Download URL | beamboard-0.0.1.tar.gz |
|---|---|
| Size | 8.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
289d54311c8cb091b3e94d8ffea6c75f646ac220c1cb866d41df5632ed7c4d34
|
|
BLAKE2b-256 checksum How to use checksums |
9b77ed79d7b98cb9b0f6ee5ed1efdefd35aa467875a714e530a1f2a238a885c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Security for beamboard 0.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.