What it does
[Bluesky](https://bsky.app) is the decentralised social network built on the [AT Protocol](https://atproto.com). This sink performs the standard two-step XRPC dance: `POST /xrpc/com.atproto.server.createSession` with `{identifier, password}` to mint a JWT, then `POST /xrpc/com.atproto.repo.createRecord` with `{repo, collection: app.bsky.feed.post, record: {text, createdAt, langs}}`. Authentication uses an [app password](https://bsky.app/settings/app-passwords) — never your main login. Post text is composed from the video title + frame count + duration, truncated to the 300-character Bluesky cap. Works against the canonical PDS (`bsky.social`) or any self-hosted PDS.
When to reach for it
- Tweet-out every peepshow run from a public ops account — clip title + duration in 300 chars
- Build a paper-trail of agent activity on a private Bluesky account (run your own PDS)
- Trigger Bluesky-side automations (firehose consumers, custom feeds) on every video your pipeline ingests
Install
npm i -g peepshowUse it
BLUESKY_IDENTIFIER="peepshow.bsky.social" \
BLUESKY_APP_PASSWORD="abcd-efgh-ijkl-mnop" \
peepshow ./clip.mp4 --sink blueskyMake it automatic
Register the sink once — every run fires it afterward. Scope by --when so it only runs for matching videos.
peepshow sinks add bluesky
peepshow sinks add bluesky --when extension=mp4,mov
peepshow sinks add bluesky --when path=/Volumes/Work/Configuration
BLUESKY_IDENTIFIERHandle (e.g. `peepshow.bsky.social`) or email used to sign in. requiredBLUESKY_APP_PASSWORDApp password (not your main login) — generate at [bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords). requiredBLUESKY_PDS_URLPDS endpoint. Default `https://bsky.social` — override for self-hosted PDSs.BLUESKY_LANGISO language tag attached to each post (`langs`). Default `en`.
Use with an LLM agent
Every peepshow sink reads its config from env vars and receives a single JSON payload on stdin. An LLM agent (Claude Code, Cursor, Windsurf, Gemini, Codex) can drive the Bluesky sink automatically when three things are true:
- the env vars below are exported in the agent's shell (or a project
.envit can load), - the
peepshowCLI is onPATH— install withnpm i -g peepshow, - a peepshow auto-sink is registered for the run (optional but recommended — makes invocation zero-argument).
1. Set the environment
# Add to ~/.zshrc, ~/.bashrc, or a project .env the agent can load
export BLUESKY_IDENTIFIER="..."
export BLUESKY_APP_PASSWORD="..."2. Register as an auto-sink
peepshow sinks add bluesky
peepshow sinks add bluesky --when extension=mp4,mov3. Example LLM session
You → drop a
.movinto Claude Code.Claude → auto-invokes
/peepshow:slides ./clip.mov. peepshow extracts frames + audio, theBlueskysink forwards the run to the configured channel. Claude replies with a summary and a link to the created record.
The transcript snippet is posted alongside the frames as a secondary message.
Write your own
A sink is any executable that reads the --emit json payload on stdin. Shell, Node, Python, Go — the spec's in docs/PLUGINS.md. Register persistent ones with peepshow sinks add-cmd 'your-command'.