From superpowers-plus
Dispatches recent screenshots to intent-driven actions (fix, explain, compare, etc.) with cross-platform folder discovery. Trigger with /sp-ss.
How this skill is triggered — by the user, by Claude, or both
Slash command
/superpowers-plus:screenshotThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!-- Credit: Allie K. Miller (https://www.linkedin.com/posts/alliekmiller_give-me-one-minute-and-ill-improve-your-share-7457142778410594304-_cdB) — original /ss concept. This skill extends that design with a formal intent dispatch table, cross-platform folder discovery, context injection, and operational guardrails. -->
Wrong skill? Take a screenshot → use your OS. Debug without a screenshot →
systematic-debugging. Build a feature →feature-development.Visual input bridge: grab screenshots and act on them.
/sp-ss [N] [intent text...]
/sp-screenshot [N] [intent text...]
Parse rule: If the first token after the command matches /^\d+$/ (one or more digit characters, no sign), it is parsed as count N. Otherwise N=1 and the entire remainder is the intent. Details:
1.5 and abc do not match the regex → become intent text0 matches the regex but fails range validation (count must be ≥1) → default to 1 with a note-1) do not match the regex → become intent text, not a defaulted countIf intent is omitted entirely, default to huh.
Examples:
| Command | Count | Intent |
|---|---|---|
/sp-ss | 1 | huh (default) |
/sp-ss huh | 1 | huh |
/sp-ss 3 fix | 3 | fix |
/sp-ss 4 compare | 4 | compare |
/sp-ss spec | 1 | spec |
/sp-ss 2 make me an infographic | 2 | free-form |
/sp-ss 0 fix | 1 | fix (invalid count, defaulted to 1) |
/sp-ss abc fix | 1 | abc fix (non-numeric, treated as intent) |
Read SCREENSHOT_DIR from ~/.codex/.env:
grep "^SCREENSHOT_DIR=" ~/.codex/.env 2>/dev/null | cut -d= -f2- — extract only this key, do NOT read the full .env file (it may contain unrelated secrets).Platform discovery:
macOS:
path=$(defaults read com.apple.screencapture location 2>/dev/null)
Quote the result when testing: [ -n "$path" ] && [ -d "$path" ]
If path exists → use it
Else → use ~/Desktop
WSL (detected via /proc/version containing "Microsoft" or "microsoft"):
Try in order:
1. username=$(cmd.exe /c "echo %USERNAME%" 2>/dev/null | tr -d '\r\n')
2. Sanitize: `username="${username//[^a-zA-Z0-9._-]/}"` (whitelist alphanumeric, dot, underscore, hyphen)
3. If empty → username=$USER
4. If still empty → username=$(whoami)
5. If all fail → stop; print: "Could not determine Windows username for WSL path resolution. Set SCREENSHOT_DIR manually in ~/.codex/.env."
Construct: `/mnt/c/Users/"${username}"/Pictures/Screenshots` (quote to prevent injection)
Note: Sanitization removes special characters; if username is unrecognizable after sanitization, fall back to next method.
Linux (non-WSL):
try $XDG_SCREENSHOTS_DIR (rarely set — not part of XDG Base Dir spec; treat
as a bonus hint, not a reliable default)
→ ~/Pictures/Screenshots
→ ~/Screenshots
Windows (PowerShell):
path = [Environment]::GetFolderPath('MyPictures') + '\Screenshots'
Note: on enterprise machines this may be a UNC path (\\server\...).
UNC paths cannot be used directly in ~/.codex/.env without escaping.
If GetFolderPath returns a UNC path, print a warning and ask the user to
set SCREENSHOT_DIR manually.
Validate before persisting: After discovery returns a path, resolve it to a canonical path using realpath to prevent symlink and traversal attacks:
resolved_path=$(realpath "$path" 2>/dev/null) || { echo "Invalid path"; return 1; }
[ -d "$resolved_path" ] || { echo "Path is not a directory"; return 1; }
path="$resolved_path"
If the check fails, fall back to the next discovery step rather than persisting an invalid path.
Persist after discovery (atomic upsert, not append-only):
Use atomic writes to prevent concurrent modification race conditions:
tmp=$(mktemp ~/.codex/.env.XXXXXX 2>/dev/null) || { echo "Cannot create temp file"; exit 1; }
trap "rm -f '$tmp'" EXIT
grep -v "^SCREENSHOT_DIR=" ~/.codex/.env > "$tmp" 2>/dev/null || true
echo "SCREENSHOT_DIR=$discovered_path" >> "$tmp"
mv "$tmp" ~/.codex/.env 2>/dev/null || { echo "Write failed"; exit 1; }
This approach:
This prevents duplicate keys and ensures consistency even with concurrent invocations.
If the write fails (read-only .env): print "Add SCREENSHOT_DIR=<path> to ~/.codex/.env to persist this setting." Then proceed with the discovered path for this session only.
List image files in the resolved folder, sorted newest-to-oldest by modification time. Use case-insensitive extension matching. Include: .png, .jpg, .jpeg, .gif, .webp, .heic, .bmp, .tif, .tiff (and their uppercase variants on case-sensitive filesystems).
Select the N most recent files.
Guardrails:
SCREENSHOT_MAX_FILE_MB MB (default 10). If the configured value is ≤0 or non-numeric, treat as 10 and warn: "Invalid SCREENSHOT_MAX_FILE_MB; using default 10MB." To get file size in bytes: stat -f%z <file> (macOS) or stat -c%s <file> (Linux/WSL); divide by 1048576 to compare against the MB limit. Print: "Skipped <filename> (exceeds limit)." If all selected files are skipped, stop and report.SCREENSHOT_MAX_IMAGES in ~/.codex/.env (default 4). If the configured value is ≤0 or non-numeric, treat as 4 (default) and warn: "Invalid SCREENSHOT_MAX_IMAGES; using default 4." If requested count > cap, warn and truncate: "Capped at N images (set SCREENSHOT_MAX_IMAGES to increase)."<path>. Have you taken a screenshot recently?"SCREENSHOT_STALENESS_MINUTES (default 30), print: "⚠️ Newest screenshot is <age> old — is this the right one?" Then proceed immediately without waiting.Read each selected file using the Read tool. For HEIC files that fail: "Could not read <filename>.heic — HEIC may not be supported here. Save screenshots as PNG (System Settings → Screenshots → Format) for best compatibility." Skip the failed file and continue with remaining selections.
Match the intent text against the table using case-insensitive semantic matching: the keyword list for each row is illustrative, not a regex. Use judgment to recognize intent. Key rules:
spec does NOT match "specification" (different concept); fix DOES match "fixing" or "broken" (same semantic family)Priority ordering (first matching row wins):
| Priority | Intent keywords | Action |
|---|---|---|
| 1 | compare, diff, vs, versus, difference | Hard gate: requires N≥2. If N=1: stop and print "compare requires N≥2 screenshots. Try /sp-ss 2 compare." Otherwise: diff/contrast the screenshots — layout, content, state changes, or visual differences. |
| 2 | spec, requirements, prd, design doc | Content-type inference first (see below). If UI/design → generate product/design spec. If code/error/terminal → offer fix instead and explain why. |
| 3 | fix, error, bug, broken, crash | Inject project context first (see below), then diagnose the problem shown and apply the fix. |
| 4 | do this, apply, implement, learn, remix | Inject project context first (see below), then identify the concept or pattern in the screenshot and adapt it to the current project's goals. |
| 5 | huh, explain, what, describe, what is | Describe the screenshot content clearly. Identify what it shows and what state it represents. |
| 6 | recap, summarize, summary, overview | One-paragraph synthesis of all N screenshots. What do they collectively show? |
| 7 | (no match) | Free-form fallback: prepend the screenshots as context and treat the full intent text as the prompt. No transformation. |
spec intent)Read the screenshot(s) and classify before dispatching:
$, >, #), stack traces, syntax highlighting, line numbers, IDE chrome.If UI/design → proceed with spec generation.
If code/error/terminal → print: "This looks like a code/error screenshot — routing to fix instead. Type /sp-ss spec anyway if you want a spec from this." Then run Project Context Injection (see below) before running the fix flow.
If ambiguous → ask the user: "Is this a UI screenshot (spec) or a code/error screenshot (fix)?"
fix and do this intents)Before interpreting the screenshot, check the current working directory for project markers. Use the Read tool on each file found:
package.json → extract name and top-level dependencies/devDependencies keysgo.mod → extract module nameCargo.toml → extract [package] namepyproject.toml → extract [project] name (preferred over setup.py if both exist)setup.py → extract name= argument (fallback if no pyproject.toml)If a marker is found, inject a 1–2 sentence prefix before interpreting the screenshot:
"Project: <name> ()."
If no marker is found in CWD: proceed without injection, no error, no mention.
| Key | Default | Description |
|---|---|---|
SCREENSHOT_DIR | auto-discovered | Folder to scan for screenshots |
SCREENSHOT_MAX_IMAGES | 4 | Max images per invocation (minimum 1) |
SCREENSHOT_MAX_FILE_MB | 10 | Max file size in MB; files exceeding this are skipped |
SCREENSHOT_STALENESS_MINUTES | 30 | Age threshold (minutes) for staleness warning |
| Platform | Discovery method | Default path if unset |
|---|---|---|
| macOS | defaults read com.apple.screencapture location | ~/Desktop |
| Linux | $XDG_SCREENSHOTS_DIR (rarely set) | ~/Pictures/Screenshots |
| WSL | Windows %USERNAME% via cmd.exe, then $USER, then whoami | /mnt/c/Users/<user>/Pictures/Screenshots |
| Windows | PowerShell GetFolderPath('MyPictures') | %USERPROFILE%\Pictures\Screenshots |
Image reading: Uses the Read tool. Claude Code and Augment Code both support image reading. Other platforms may vary — if images fail to load, confirm your platform supports image input.
iCloud on macOS: If screenshots are saved to iCloud Drive, the resolved path may be inside ~/Library/Mobile Documents/. Files may not be immediately readable due to sync latency. If listing succeeds but Read fails, wait a moment and retry, or move screenshots to a local folder.
| Situation | Response |
|---|---|
SCREENSHOT_DIR path vanished | Re-run discovery, upsert .env with new path |
| No image files | "No screenshots found in <path>." |
| All files exceed size limit | "All selected screenshots exceed the SCREENSHOT_MAX_FILE_MB limit. Resize or save as PNG, or increase the limit in ~/.codex/.env." |
| Re-discovery also fails | Print: "Screenshot folder not found and auto-discovery failed. Set SCREENSHOT_DIR manually in ~/.codex/.env." |
Read-only .env | Print path for manual addition, continue for session |
| HEIC unreadable | Skip with PNG recommendation, continue with remaining files |
compare with N=1 | Hard stop, prompt user to add count |
| Count > cap | Warn, truncate to cap |
| Count > available | Use all available, note shortfall |
| WSL username resolution fails | Stop, ask user to set SCREENSHOT_DIR manually |
| UNC path from Windows enterprise | Warn, ask user to set SCREENSHOT_DIR manually |
Trace A (/sp-ss 2 fix, first-discovery): No SCREENSHOT_DIR key → run macOS discovery (fallback ~/Desktop) → list 4 images, select 2 → read both → fix intent + project context injection (React+TS detected).
Trace B (/sp-ss 1 compare, hard-gate): Read cached SCREENSHOT_DIR from .env → list 6 images → hard gate: N=1 < 2 required → STOP with "compare requires N≥2".
Trace C (/sp-ss huh, stale path): Read stale SCREENSHOT_DIR (/Volumes/External, unmounted) → re-discover to ~/Desktop → atomically update .env via temp+grep+mv → list 3 images, staleness warning (47 min > 30 min threshold) → huh intent dispatch.
npx claudepluginhub bordenet/superpowers-plus --plugin superpowers-plusGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.