shotnote is a macOS-only CLI that pulls screenshots from Photos.app and turns each image into a Markdown note with an OpenAI vision model.
If you are like me, you take screenshots of short videos on your phone. When watching low-signal AI-generated short videos, often the only things worth keeping are the GitHub repo URL and a few keywords for further learning. This tool is for you.
It is built for a simple workflow:
- Capture screenshots on your phone.
- Let iCloud Photos sync them to your Mac.
- Run
shotnoteto pull new screenshots into~/.shotnote/inbox/. - Generate one note per image in
~/.shotnote/notes/. - Copy each newly generated note into
~/.shotnote/export/for downstream consumption.
- macOS
- Node.js 20+
Photos.appwith your screenshots already synced- Xcode Command Line Tools so
xcrun swiftis available - An OpenAI API key
Install Command Line Tools if needed:
xcode-select --installShotnote is not published to npm yet. Install it from source:
pnpm install
pnpm build
pnpm link --globalAfter that, the shotnote command is available in your shell.
Run any Shotnote command once to bootstrap the working directory:
shotnote list-albumsThis creates:
~/.shotnote/
├── inbox/
├── notes/
├── export/
├── prompts/
│ └── analyze-screenshot.md
├── state/
│ ├── synced.json
│ └── analyzed.json
├── logs/
├── bin/
└── config.json
Then edit ~/.shotnote/config.json and add your API key:
{
"source": {
"type": "photos-album",
"albumName": "Screenshots"
},
"analysis": {
"provider": "openai",
"model": "gpt-4.1-mini",
"promptPath": "~/.shotnote/prompts/analyze-screenshot.md",
"apiKey": "your_key_here"
}
}Now try a small sync first:
shotnote sync --limit 5
shotnote analyzeUse shotnote sync --limit 5 for the first sync bootstrap. After that, use shotnote sync for normal incremental syncing.
Or run both steps together:
shotnote run --limit 5On the first sync, macOS may ask for permission to access your photo library. Grant it.
Shotnote reads configuration from:
~/.shotnote/config.json- environment variables
Environment variables override config.json:
OPENAI_API_KEYSHOTNOTE_ALBUM_NAMESHOTNOTE_MODELSHOTNOTE_PROMPT_PATH
If you use a network proxy to reach OpenAI, set standard proxy variables before running Shotnote:
https_proxyhttp_proxyall_proxy
Example:
export https_proxy=http://127.0.0.1:7897
export http_proxy=http://127.0.0.1:7897
export all_proxy=socks5://127.0.0.1:7897Pull new screenshots from Photos.app into ~/.shotnote/inbox/.
shotnote sync --limit 20
shotnote sync--limit only affects the first sync. After Shotnote has synced once, later syncs pull everything newer than the last successful sync.
Recommended pattern:
- first sync:
shotnote sync --limit 20 - later syncs:
shotnote sync
By default, Shotnote reads from the system Screenshots collection. This is a smart collection in Photos.app, not a normal user album.
Analyze screenshots already in ~/.shotnote/inbox/, write Markdown notes into ~/.shotnote/notes/, and copy newly generated notes into ~/.shotnote/export/.
shotnote analyzeTo re-run one image after changing the prompt:
shotnote analyze --image 2026-03-24-existing.png --force--image only accepts a file name from ~/.shotnote/inbox/. --force requires --image.
When you force a re-run for the same image, Shotnote keeps only the latest note for that image hash.
Run sync and then analyze:
shotnote run
shotnote run --limit 10run also copies newly generated notes into ~/.shotnote/export/.
List user-created albums in Photos.app:
shotnote list-albumsUse this when you want to point Shotnote at a custom album with SHOTNOTE_ALBUM_NAME or config.json.
Screenshots usually does not appear here because it is a system smart collection, not a user-created album.
Shotnote stores the analysis prompt in:
~/.shotnote/prompts/analyze-screenshot.md
The file is created automatically on first run. Edit it directly to change classification and summary behavior, then re-run one image:
shotnote analyze --image 2026-03-24-existing.png --forceIf you want macOS to run Shotnote on a schedule and push ~/.shotnote/export/ to another machine, use launchd instead of cron.
See LAUNCHD.md.
That is expected. list-albums only shows user-created albums. The default Screenshots source is handled separately.
Use --limit:
shotnote sync --limit 5This limit is only for the initial sync bootstrap. After the first successful sync, use shotnote sync.
Shotnote tracks processed images in ~/.shotnote/state/analyzed.json. Re-run a single image with:
shotnote analyze --image <filename> --forceCheck your proxy settings and try exporting https_proxy, http_proxy, or all_proxy before running Shotnote.
pnpm test
pnpm build