ScreenQuery is a menu-bar utility for Windows and macOS. Hold Shift and press S and P together to capture the full desktop. It can save a PNG, send the image to an OpenAI vision model, or both, then show the result in a floating status window.
It is one Python application, packaged the same way EyesRhythm ships both platforms from one project: a Windows .exe and a macOS .dmg. A native Xcode app would only run on a Mac.
The app ships with no API key. Paste your own in Settings. It is stored in the system keychain (macOS Keychain or Windows Credential Manager), never in settings.json and never in this repository.
A Mac build is published as a disk image you can download. Pick the file that matches Apple menu → About This Mac:
- Apple silicon (M1 or later): ScreenQuery-arm64.dmg
- Intel: ScreenQuery-x86_64.dmg
Both files are on the v1.0.0-test prerelease. GitHub rebuilds them from this branch on a Mac.
The build is not notarized, so macOS warns the first time.
- Open the DMG and drag ScreenQuery onto Applications.
How to Open.txtin the disk image repeats these steps. - Eject the disk image.
- In Applications, Control-click ScreenQuery and choose Open, then Open again.
- If macOS says the app is damaged, run this in Terminal and open the app again:
xattr -dr com.apple.quarantine /Applications/ScreenQuery.app- Settings opens in front. The menu-bar title is SQ.
- Allow Screen Recording and Input Monitoring, quit ScreenQuery, and open it again. macOS ties those grants to this copy of the app.
- Hold Shift and press S and P.
- Windows 10 or later, or macOS 12 or later
- Python 3.10 or later, with Tk (included in the official Windows and python.org macOS installers)
- An OpenAI API key only if you turn on Send to OpenAI
From the repository root:
python -m venv .venvWindows:
.venv\Scripts\activate
python -m pip install -r requirements.txt
python -m screenquerymacOS:
source .venv/bin/activate
python -m pip install -r requirements.txt
python -m screenquerypython -m screenquery --check prints the version and does not open a window.
On macOS the menu title is SQ (no Dock icon when PyObjC is installed). On Windows the icon sits in the system tray. The first launch opens Settings. Later launches open Settings only when the tray icon could not be created.
Capture Now in the menu runs the same path without the hotkey.
Hold Shift, then press S and P (either letter first). The chord fires once until you release S or P. Releasing Shift cancels a partial chord. Key repeat does not capture again. Caps Lock does not count as Shift.
The listener only observes keys. It does not swallow them, so S and P still reach the app in front.
| System | What to grant | Why |
|---|---|---|
| macOS | Screen Recording | Capture the display |
| macOS | Input Monitoring | Global Shift+S+P hotkey. Allow Accessibility too if macOS lists the prompt there |
| Windows | No privacy pane | The hotkey is a global keyboard hook |
macOS ties each grant to the exact program. A copy started from a terminal and ScreenQuery.app from the DMG are different apps. After you allow access, quit ScreenQuery and open it again.
The packaged Mac app declares NSScreenCaptureUsageDescription. Use Settings → Permissions to jump to Screen Recording, Input Monitoring, or Accessibility. If PyObjC Quartz is installed, Settings can also request Screen Recording and Input Monitoring directly.
Windows has no equivalent prompt. If Shift+S+P does nothing, another program may already own that chord. Capture Now still works.
From the menu: Settings…
- Save screenshot and Send to OpenAI are independent. Enable one or both. Both start out as save on, OpenAI off.
- Save location
- Default:
~/ScreenQuery/<YYYY-MM-DD>/ScreenQuery-<yyyyMMdd-HHmmss-SSS>.png - Custom folder: PNGs are written directly in the folder you pick (no extra date directory).
- If that filename already exists, ScreenQuery appends
-2,-3, and so on.
- Default:
- OpenAI
- Paste a key and choose Save Key. The item is service
com.screenquery.ScreenQuery, accountopenai-api-key. Remove Key deletes it. - Base URL defaults to
https://api.openai.com/v1. The client posts to<base>/chat/completions.https://api.openai.comis normalized to the/v1endpoint. A full…/chat/completionsURL is used as-is.httpis rejected except forlocalhost/127.0.0.1. Userinfo in the URL is stripped. - Model defaults to
gpt-4o.gpt-4o-miniandgpt-4.1are shortcuts; any Chat Completions vision model name is accepted.
- Paste a key and choose Save Key. The item is service
- Launch at login writes a LaunchAgent (
com.screenquery.ScreenQuery) on macOS, or anHKCU\...\Runvalue namedScreenQueryon Windows.
Preferences live in:
- macOS:
~/Library/Application Support/ScreenQuery/settings.json - Windows:
%APPDATA%\ScreenQuery\settings.json
If a key was ever written into that file, ScreenQuery removes it on the next load. If both actions are off, the hotkey does not capture; the status window tells you to turn one on.
- Hides the status window, then captures every display as one image (the cursor is included). The Settings window can still appear in the shot if it is open.
- If save is on, writes a full PNG to the folder above.
- If OpenAI is on, the status window says it is asking, then downscales the long edge to at most 2048 pixels, JPEG-compresses the image (about 4.5 MB or smaller), and sends a Chat Completions request. The prompt asks the model to answer or explain whatever is on screen. The key is sent only as a Bearer token. If a model rejects
max_tokens, ScreenQuery retries once withmax_completion_tokens. A save error does not cancel the OpenAI request. - Shows a borderless, always-on-top window at the bottom-right of the primary screen. On macOS it is a non-activating help window. It reports the save path and the model reply, or a short error. It dismisses on its own (about 8 seconds for a save, 12 for an error, 20 for an answer), waits while the pointer is over it or while OpenAI is still responding, and closes if you click the title or ✕. Copy copies the answer. Show in Folder reveals the PNG.
The tests use only the Python standard library:
python -m unittest discover -s tests -vThey cover the Shift+S+P state machine, default and custom save paths, Chat Completions URL and JSON construction (the API key is not part of the body), response parsing, the max_tokens retry, keychain round-trip, leaked-key removal, and launch-item text.
On Windows, from the repository root:
powershell -ExecutionPolicy Bypass -File scripts\build-windows.ps1The script installs the build dependencies and writes a windowed one-file dist\ScreenQuery.exe.
On a Mac, from the repository root:
chmod +x scripts/build-dmg.sh
./scripts/build-dmg.shThe script runs PyInstaller --windowed, marks the app as an agent (LSUIElement), ad-hoc signs it with Hardened Runtime, and packs dist/ScreenQuery.app plus an Applications alias into dist/ScreenQuery.dmg.
scripts/build-dmg.sh exits immediately on any system that is not macOS. This repository can be unit-tested on Linux, but the DMG and the exe have to be built on the matching OS.
Sign with a Developer ID certificate and notarize when you distribute outside your own Mac:
SIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" \
NOTARY_PROFILE="your-notarytool-keychain-profile" \
./scripts/build-dmg.shCreate the notary profile once with xcrun notarytool store-credentials. The script submits the app, staples the ticket, builds the DMG, then submits the DMG. The app is not sandboxed: a global hotkey and a user-chosen save folder do not fit the App Sandbox. scripts/entitlements.plist only relaxes library validation so a notarized PyInstaller binary can start.
The screenshot stays on the machine unless Send to OpenAI is on. In that case the JPEG is posted to the base URL you configured, with your keychain key as a Bearer token. Preferences store the toggles, folder path, base URL, and model name.
screenquery/— hotkey, capture, keychain, settings, overlay, traytests/— standard-library unit testsscripts/build-dmg.sh— macOS app and DMGscripts/build-windows.ps1— Windows executablescripts/entitlements.plist— hardened-runtime exceptions for the Mac build.github/workflows/macos-dmg.yml— builds the Apple silicon and Intel disk images and publishes the test release
- Exercise save only, OpenAI only, and both on the downloaded app.
- Notarize with an Apple Developer ID before sharing a build that opens without the Gatekeeper warning.