peepshow/ sinks/ zoom

Reel #88 Zoom Team Chat

peepshow sink / zoom

ZoomPost the run summary as a Zoom Team Chat message to a user or channel.

POSTs `/v2/chat/users/me/messages` with the summary text. Use server-to-server OAuth to mint short-lived access tokens, then DM a teammate or post to a channel JID.

drop · process · zoom

What it does

[Zoom](https://zoom.us) is the meeting platform; [Zoom Team Chat](https://developers.zoom.us/docs/api/chat/) is its persistent messaging layer. This sink posts a markdown-flavoured summary of each peepshow run — title, frame count, duration, resolution, codec, and a truncated transcript preview — to a recipient. The recipient is either a user (DM, by email via `ZOOM_TO_USER`) or a channel (group post, by channel JID via `ZOOM_TO_CHANNEL`); the two are mutually exclusive. Authentication is a Bearer access token typically minted by Zoom's [Server-to-Server OAuth flow](https://developers.zoom.us/docs/internal-apps/s2s-oauth/). The Cloud Recording API only exposes *retrieval* of Zoom-hosted recordings — there is no public upload surface for arbitrary media, so chat messaging is the practical integration that works against any Zoom account today.

When to reach for it

  • DM a teammate when an agent finishes processing a video (release video, customer-call recap, sprint demo)
  • Post every peepshow run into a `#video-pipeline` Zoom channel as a paper-trail
  • Bolt a video-summary stage onto an existing Zoom workflow without writing a Zoom Marketplace app from scratch

Install

npm i -g peepshow

Use it

ZOOM_ACCESS_TOKEN="$(./refresh-zoom-token.sh)" \
ZOOM_TO_USER="alice@example.com" \
peepshow ./standup.mp4 --sink zoom

Make it automatic

Register the sink once — every run fires it afterward. Scope by --when so it only runs for matching videos.

peepshow sinks add zoom
peepshow sinks add zoom --when extension=mp4,mov
peepshow sinks add zoom --when path=/Volumes/Work/

Configuration

  • ZOOM_ACCESS_TOKEN OAuth2 access token (Bearer header). Refresh before each invocation — tokens expire in 1 hour. required
  • ZOOM_TO_USER Recipient email for a user DM. Mutually exclusive with `ZOOM_TO_CHANNEL`.
  • ZOOM_TO_CHANNEL Channel JID for a channel post. Mutually exclusive with `ZOOM_TO_USER`.
  • ZOOM_TITLE_PREFIX Prefix prepended to the message title. Default `peepshow`.
  • ZOOM_API_URL Override the API base URL. Default `https://api.zoom.us`.
  • ZOOM_TRANSCRIPT_MAX Max transcript characters included in the message. Default 2000.
  • PEEPSHOW_FRAME_BASE_URL When set, the first frame URL is appended as a link below the summary.

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 Zoom sink automatically when three things are true:

  • the env vars below are exported in the agent's shell (or a project .env it can load),
  • the peepshow CLI is on PATH — install with npm 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 ZOOM_ACCESS_TOKEN="..."

2. Register as an auto-sink

peepshow sinks add zoom
peepshow sinks add zoom --when extension=mp4,mov

3. Example LLM session

You → drop a .mov into Claude Code.

Claude → auto-invokes /peepshow:slides ./clip.mov. peepshow extracts frames + audio, the Zoom sink 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'.