Hand Claude the picture on your clipboard in one command.

Hand Claude the picture on your clipboard in one command. Snip part of your screen, type /shot, and Claude gets the picture without you saving a file or finding a path.
/shot saves the clipboard picture and puts a message for Claude in your prompt box. Press Enter to send it./shot is the band lined up? puts your own question in with it.Shot saves the picture as a PNG in your temp folder, then writes one message naming that file into your prompt box. Claude opens the file itself. It uses Windows' own clipboard on Windows, wl-paste or xclip on Linux, and pngpaste on macOS if you have it installed. The picture stays on your machine.
Nothing goes to any service from the mod itself. Here is each thing, plainly.
What it sends, and where.
$.process.run starts the saver program below on your machine. $.prompt.fill writes text into your prompt box without sending it.Which programs it runs, and why.
powershell.exe -NoProfile -Command with this script:Add-Type -AssemblyName System.Windows.Forms; $i = [System.Windows.Forms.Clipboard]::GetImage(); if ($i) { $p = Join-Path $env:TEMP ("shot-" + (Get-Date -Format yyyyMMdd-HHmmss) + ".png"); $i.Save($p); $p }
wl-paste:sh -c 'p="${TMPDIR:-/tmp}/shot-$(date +%Y%m%d-%H%M%S).png"; wl-paste --type image/png > "$p" 2>/dev/null && [ -s "$p" ] && echo "$p"'
xclip:sh -c 'p="${TMPDIR:-/tmp}/shot-$(date +%Y%m%d-%H%M%S).png"; xclip -selection clipboard -t image/png -o > "$p" 2>/dev/null && [ -s "$p" ] && echo "$p"'
pngpaste if you installed it:sh -c 'p="${TMPDIR:-/tmp}/shot-$(date +%Y%m%d-%H%M%S).png"; pngpaste "$p" 2>/dev/null && echo "$p"'
/shot.What it puts in the prompts it submits.
Here is a screenshot I just took: <the PNG's path>, a blank line, then the words you typed after /shot.Look at it and tell me what you see.What each hook does.
session.start: adds the /shot command.command.run for shot: saves the clipboard picture, then fills your prompt box with the message above.Tested with Claude Code 2.1.287 on Windows.
See every Rostech mod, live, at rostech.app.
hooks/register.ts 42 lines1import type { EngineInterface, Register } from 'claude-code'
2
3// Saves the picture on the clipboard as a PNG and prints its path, or prints
4// nothing when the clipboard holds no picture. Windows first, then Wayland,
5// then X11; macOS needs `pngpaste` installed.
6const SAVERS: readonly (readonly string[])[] = [
7 [
8 'powershell.exe', '-NoProfile', '-Command',
9 'Add-Type -AssemblyName System.Windows.Forms; $i = [System.Windows.Forms.Clipboard]::GetImage(); ' +
10 'if ($i) { $p = Join-Path $env:TEMP ("shot-" + (Get-Date -Format yyyyMMdd-HHmmss) + ".png"); $i.Save($p); $p }',
11 ],
12 ['sh', '-c', 'p="${TMPDIR:-/tmp}/shot-$(date +%Y%m%d-%H%M%S).png"; wl-paste --type image/png > "$p" 2>/dev/null && [ -s "$p" ] && echo "$p"'],
13 ['sh', '-c', 'p="${TMPDIR:-/tmp}/shot-$(date +%Y%m%d-%H%M%S).png"; xclip -selection clipboard -t image/png -o > "$p" 2>/dev/null && [ -s "$p" ] && echo "$p"'],
14 ['sh', '-c', 'p="${TMPDIR:-/tmp}/shot-$(date +%Y%m%d-%H%M%S).png"; pngpaste "$p" 2>/dev/null && echo "$p"'],
15]
16
17async function save($: EngineInterface): Promise<string> {
18 for (const argv of SAVERS) {
19 const ran = await $.process.run(argv, { timeoutMs: 10000 }).catch(() => null)
20 const path = ran && ran.exitCode === 0 ? ran.stdout.trim().split(/\r?\n/).pop() ?? '' : ''
21 if (path) return path
22 }
23 return ''
24}
25
26export const register: Register = on => {
27 on('session.start', async ($, e, next) => {
28 await $.command.register({ name: 'shot', description: 'Hand Claude the picture on your clipboard. /shot, or /shot <what to look for>' })
29 return next(e)
30 })
31
32 on('command.run', { command: 'shot' }, async ($, e) => {
33 const path = await save($)
34 if (!path) return { text: 'No picture on the clipboard. Snip or copy one first, then /shot.' }
35 const ask = e.args.trim() || 'Look at it and tell me what you see.'
36 // A command cannot send a prompt while it runs, so the message goes into the
37 // prompt box ready to send: one Enter, and room to add words first.
38 await $.prompt.fill({ text: `Here is a screenshot I just took: ${path}\n\n${ask}`, mode: 'replace' })
39 return { text: `📸 Saved: ${path}. Press Enter to send it to Claude.` }
40 })
41}
42