# scrot Clipboard sync across your own devices, and screenshot → instant public link. One blob store, one small server, two thin CLI scripts. ## Why Two small itches, solved by the same mechanism — see [PROPOSAL.md](./PROPOSAL.md) for the full design rationale, and why this isn't just `wisp` or `flit` again: - **Clipboard sync**: copy on one machine, pull it on another, without a cloud clipboard manager that might get paywalled or discontinued. - **Screenshot → link**: capture a region, get a shareable URL on your clipboard immediately, without an Imgur/CloudApp-style third-party uploader. ## Model A single `blobs` table with a `kind`: - `clip` — private, text. Pull-only — your other devices ask "what's the latest clip?" No public URL is ever minted. - `shot` — public, image. Upload returns a short link (`/s/:id`) anyone with the link can view — no auth required, same trust level as handing someone a photo link. Single shared `DEVICE_TOKEN` gates every write and the private clip-read — this is single-user infrastructure across your own machines, not a multi-tenant service, so there's no per-device registry to manage. No end-to-end encryption: unlike `wisp` (built for sharing with other people), this server is already fully trusted homelab infra, same trust level as `keep`/`trace`. Adding client-side crypto here would defend against a threat that doesn't apply. ## Server ```bash cd server npm install DEVICE_TOKEN=... npm run dev ``` See [.env.example](./.env.example) for the full config surface (`CLIP_TTL_SECONDS`, `SHOT_TTL_SECONDS`, `MAX_UPLOAD_BYTES`, ...). ## CLI Four scripts in [cli/](./cli/), each meant to sit behind a keybinding: - `scrot-clip-push` — pushes the current system clipboard as a `clip`. - `scrot-clip-pull` — fetches the latest `clip` into the system clipboard. - `scrot-shot` — captures a region screenshot, uploads it as a `shot`, copies the resulting public link to the clipboard. - `scrot-onboard` — prints (and, with `qrencode` installed, renders as a terminal QR code) the link that onboards a phone onto the PWA below. Each needs `SCROT_SERVER` and `DEVICE_TOKEN` in the environment — source them from `~/.config/scrot/env` (gitignored, not tracked here). Wayland (`wl-paste`/`wl-copy`/`grim`+`slurp`) and X11 (`xclip`/`maim`) are both supported, auto-detected via `$WAYLAND_DISPLAY`. ## Mobile / PWA The server also serves a small installable web app (`server/public/`) — paste-or-share text as a `clip`, upload/share an image as a `shot`, and pull the latest clip back down. No separate mobile client. Onboarding a phone onto the shared `DEVICE_TOKEN`: run `scrot-onboard` and open the printed link (or scan the QR) on the phone. That saves the token into the page's `localStorage` and mirrors it into a cookie. Add the app to the home screen and reopen it once — that re-fetches `/manifest.webmanifest` with the token now baked into its `share_target.action` URL (see [server/src/manifest.ts](./server/src/manifest.ts)), which is what makes "Share to scrot" show up in the OS share sheet for photos and selected text. No service worker involved: the share sheet POSTs straight to `/share` ([server/src/share.ts](./server/src/share.ts)), which checks the token in the query string (custom headers aren't available to a share-target POST) and inserts the blob through the same path as `POST /api/blobs`. ## Status Scaffolded: server (routes, auth, TTL cleanup, SQLite, PWA share target) and CLI scripts written, not yet run against a real deployment or wired into `keep`. Next: `npm install` + smoke test locally, then a first deploy. ## Deploy Mirrors the rest of the project family — `Dockerfile` + `docker-compose.yml`, named volume for `data/`, env-driven config. Not yet migrated onto `keep` for secret delivery (tracked in goonk's `FUTURE.md` ops migration list alongside every other project still on hand-copied `.env`).