A Vellum assistant plugin that ships an app with two buttons:
- Share screen — opens the browser's own screen picker, exactly like sharing into Google Meet. You choose a screen, window, or tab.
- Take screenshot — counts down from 3, grabs a single frame of whatever you are sharing, and saves it as a PNG in your assistant's workspace.
The difference from Meet is what happens in between: nothing. No video is streamed to the assistant, and no frames leave the browser until you press the second button. The only thing that ever reaches the workspace is a still you asked for.
While a share is live the first button becomes Stop sharing, so the whole surface stays at two buttons.
assistant plugins install https://github.com/vellum-ai/screenshare
Then open the screen-share app from the workspace panel.
| Surface | What it does |
|---|---|
apps/screen-share/ |
The two-button UI, compiled from src/ to dist/ by the host |
routes/screenshots.ts |
POST saves a captured frame; GET lists what's stored |
routes/settings.ts |
Serves the config.json values the app needs at runtime |
skills/screen-share-screenshots/ |
Teaches the assistant to find and look at a capture |
hooks/init.ts |
Creates the screenshot directory on boot |
<workspaceDir>/plugins/screenshare/data/screenshots/, named for when they were
taken and what was shared:
screenshot-20260801-161500-screen-1.png
screenshot-20260801-162238-chrome-vellum-docs.png
The filename carries everything, so there is no sidecar metadata and no index to
fall out of sync — the directory listing is the store. Per the plugin contract
all durable state lives in data/, so uninstalling the plugin takes the
screenshots with it.
Saving a file into the workspace does not put it in front of the model, so the
plugin ships a skill for that. Ask your assistant something like "what's on
my screen?" or "read the error in the screenshot I just took" and it loads
screen-share-screenshots, which tells it to list the captures and read the one
you mean with the built-in file_read tool — that already returns PNGs as images
for visual analysis.
A skill rather than a tool, deliberately. A tool's name, description, and input schema sit in the model's context on every turn whether or not it is ever called, and looking at a screenshot is only occasionally relevant. A skill costs nothing until the conversation matches it, and it can carry judgement a schema can't: which capture "what's on my screen" means, when to read several, to quote error text verbatim, and not to guess when nothing has been captured yet.
The skill's scripts/list-screenshots.ts prints the store newest-first as
<captured-at> <size> <absolute-path>, so the assistant can hand a path
straight to file_read. It reuses src/screenshots.ts for the listing rather
than reimplementing the ordering, which is why that module takes its directory as
an argument and imports nothing from the host — a skill script runs as a plain
bun process, where @vellumai/plugin-api would not resolve.
config.json at the plugin root. Edit it in place — it is a preserved entry, so
your changes survive upgrades.
| Key | Default | Meaning |
|---|---|---|
countdownSeconds |
3 |
Seconds before the shutter. 0 captures immediately; max 60. |
maxWidth |
1920 |
Screenshots wider than this are scaled down before being saved. |
retainCount |
200 |
How many screenshots to keep; older ones are pruned after a save. |
Every value is clamped to a sane range and falls back to its default if it is missing or malformed, so a bad edit degrades rather than breaking capture.
The host's plugin source watcher compiles apps/screen-share/src/ into a sibling
dist/ on change — there is no build step to run, and dist/ is not tracked.
The bundler is esbuild with react/react-dom aliased onto preact/compat; the
entry point is src/main.tsx and src/index.html is the shell.
apps/screen-share/tsconfig.json mirrors the host's compiler flags so editors and
tsc --noEmit agree with the real build.