review-image
review-image
Use this skill when you want a cheap vision-model opinion on an image before doing heavier work.
When to use
- Quick VRT sanity checks
- Detect obviously broken, blank, malformed, or suspicious inputs
- Ask a model whether a screenshot or generated image matches a prompt
- Add a simple image-review gate to CI
Requirements
- Deno
OPENROUTER_API_KEYorOPENROUTER_KEY
Invocation
Both scripts are executable Deno files with shebang #!/usr/bin/env -S deno run --allow-env --allow-net --allow-read. Run them directly — no deno run wrapper needed.
When the skill is APM-installed, the scripts live under ~/.claude/skills/review-image/scripts/. Examples below use the ~/... form, which is shell-expanded. In non-shell exec contexts (e.g. child_process.spawn without shell: true) both ~ and $HOME stay literal — substitute the resolved absolute path (/Users/<you>/.claude/skills/review-image/scripts/...).
Flags can appear before, between, or after the positional args. --model accepts both --model X and --model=X. Both scripts write program output to stdout and logs/errors to stderr — but only the JSON-emitting modes (CI gate always; freeform with --json) are safe to pipe straight into jq / JSON.parse. Freeform default mode is prose, not JSON.
Scripts
Freeform review — review-image.ts
~/.claude/skills/review-image/scripts/review-image.ts <image-path-or-url> "<prompt>" [--model <id>] [--json]
# example with flag interleaved with positionals:
~/.claude/skills/review-image/scripts/review-image.ts ./shot.png "VRT diff broken?" --model google/gemini-2.5-flash
Default output: plain prose on stdout (the model's reply, single block).
With --json: stdout becomes a single JSON object, safe to pipe into jq / JSON.parse:
{
"id": "gen-...",
"model": "<resolved>",
"text": "<freeform answer>",
"usage": { "prompt_tokens": 123, "completion_tokens": 45, "total_tokens": 168, "cost": 0.0001 },
"raw": { /* full upstream OpenRouter response, opaque */ }
}
Read .text for the answer; .usage.cost (USD) and .usage.total_tokens for cost telemetry.
Exit codes: 0 on success, 1 on any error (missing API key, network/HTTP failure, malformed response).
CI gate — review-image-ci.ts
~/.claude/skills/review-image/scripts/review-image-ci.ts <image-path-or-url> "<prompt>" [--model <id>]
Always prints a single JSON object on stdout (the --json flag is silently ignored without warning — output is always JSON):
{
"decision": "pass",
"summary": "<short reason>",
"issues": [],
"model": "<resolved>",
"usage": { "prompt_tokens": 123, "completion_tokens": 45, "total_tokens": 168, "cost": 0.0001 },
"rawText": "<unparsed model reply>"
}
issues is always an array of strings (never null / never omitted) — empty on pass, populated with one or more reasons on fail. usage keys match the freeform script and may include additional OpenRouter-passthrough fields (e.g. is_byok, *_details); treat the four listed keys (prompt_tokens, completion_tokens, total_tokens, cost) as the stable contract.
The CI gate wraps your prompt internally with strict JSON-schema instructions for the model. Write <prompt> as plain English describing the gate criteria — do not include schema, formatting directives, or "respond in JSON" yourself; those are supplied automatically and your additions can conflict with them.
Exit codes:
0—decision: pass2—decision: fail1— script error (missing API key, network/HTTP failure, malformed model response). Treat as neither pass nor fail in CI; do not gate on$? -ne 0alone.
Writing prompts
The <prompt> argument is plain English describing what to check. Use these as starting templates:
CI gate (gate-criteria style) — describe what should be there and what counts as failure. Avoid vague "is this broken?"; pixel art and intentionally low-res content fail naively-worded gates:
"This image is {expected: a Playwright screenshot of /dashboard / a generated cactus illustration / ...}. Pass if it shows recognizable intended content (any style, including pixel art, low-res, or stylized). Fail only if blank, all-black/all-white, corrupted, an error page, or visibly malformed."
Freeform (diagnostic style) — ask for specifics so the prose answer is actionable:
"This image is supposed to be {expected subject}. Describe what you see and call out any visual artifacts, broken layout, color anomalies, or signs of file corruption."
Default model
google/gemini-2.5-flash-lite
Override per call with --model or globally with OPENROUTER_MODEL.
More from mizchi/skills
empirical-prompt-tuning
Methodology for iteratively improving agent-facing instructions (skills / slash commands / CLAUDE.md / code-gen prompts) by having a bias-free executor run them and evaluating two-sidedly (executor self-report + instruction-side metrics) until improvements plateau. Use after creating or revising a prompt or skill.
38gh-fix-ci
Debug or fix failing GitHub PR checks running in GitHub Actions. Inspects checks/logs via `gh`, drafts a fix plan, and implements only after explicit approval. Out of scope: external CI (e.g. Buildkite) — report only the details URL.
9tech-article-reproducibility
Evaluate the reproducibility of technical articles. Dispatch a subagent to simulate a first-time reader reproducing the work locally and list missing information. Use as the final check on a draft before publication.
8retrospective-codify
On task completion, pair "what failed first" with "what finally worked" and codify the should-have-known-it insight as an ast-grep rule, skill, or CLAUDE.md rule. Use after trial-and-error solutions to spare future-you (or another agent) the same trap. Trigger phrases: "codify today''s lessons," "make it a skill," "drop it into lint."
8playwright-test
Best practices and reference for Playwright Test (E2E). Covers how to write tests, avoiding fixed waits, network triggers, DnD, shard/retry setup on GitHub Actions, and more. Use when writing, reviewing, or configuring CI for Playwright tests.
6ast-grep-practice
Operate ast-grep as a project lint tool. Covers sgconfig.yml, fix/rewrite rules, constraints, transform, testing, and CI. Use when writing rules ast-grep can express but general-purpose linters cannot.
6