local-vision-ollama
Analyze images using local Ollama vision model (qwen3.5:4b) with automatic pre-resizing and filename sanitization for reliable processing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Analyze images using local Ollama vision model (qwen3.5:4b) with automatic pre-resizing and filename sanitization for reliable processing.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use Strata, the Legacy Code Labs macOS visual-spec app, through its local Streamable HTTP MCP server. Trigger when Codex needs to create, read, validate, update, version, diff, or restore Strata diagrams; build visual specs from user flows, discovery trees, architecture sketches, or D2; diagnose Strata MCP setup; or verify a feature against a shared Strata canvas.
Use Clarity, the LegacyCodeHQ structural design CLI, for dependency impact graphs, architecture/refactoring verification, before-commit design checks, code review context, cycle/module/workspace exploration, AGENTS.md Clarity setup, or rebuilding/probing Clarity command availability. Use when Codex needs to run or interpret clarity show, watch, languages, extensions, modules, cycles, workspace, setup, or version-specific Clarity commands.
Plan, build, harden, and review Kotlin backend services with Spring Boot, Ktor, coroutines, typed configuration, persistence, migrations, testing, security, resilience, and operations. Use for Kotlin HTTP APIs, workers, service refactors, production-readiness reviews, or JVM backend architecture decisions.
Reliability-first Kotlin skill for implementing, refactoring, or reviewing Kotlin libraries, CLIs, JVM modules, shared domain code, coroutine code, and Java interop boundaries. Use when work needs null-safety discipline, value and sealed types, idiomatic scope-function use, typed errors, structured concurrency, testing, or JVM quality gates.
Reliability-first Python skill for implementing, refactoring, or reviewing Python packages, CLIs, services, scripts, async code, tests, and typed modules. Use when work needs type hints, dataclasses, boundary parsing, exception design, context managers, asyncio cancellation, packaging, pytest or unittest strategy, ruff, mypy, pyright, or runtime safety.
Save the most recent visible conversation text from the active Codex thread into a timestamped Markdown checkpoint file in the current repo root. Use when the user asks to back up the last few chat messages, dump recent thread context to disk, preserve a resume point before context loss, or create a lightweight conversation recovery file.
| name | local-vision-ollama |
| description | Analyze images using local Ollama vision model (qwen3.5:4b) with automatic pre-resizing and filename sanitization for reliable processing. |
| version | 1.0.0 |
| author | hermes |
| model | qwen3.5:4b |
Analyze images locally using the qwen3.5:4b model running on Ollama. Handles the key pitfalls: oversized images causing timeouts, Unicode filenames breaking file paths, and batch processing.
http://localhost:11434~/.hermes/config.yaml auxiliary.vision section~/.hermes/.env AUXILIARY_VISION_* (takes precedence over config.yaml)Full-resolution Retina screenshots (10+ MB, 2880x1800+) generate ~6,500+ vision tokens. The ViT prefill is O(n^2) on patch count and WILL timeout at 120s.
Target: max 800px longest edge. This produces ~600 tokens, processes in 10-20s instead of 90-120s+.
# Single image
sips -Z 800 /path/to/input.png --out /tmp/vision_input.png
# Batch - copy and resize all images in a folder
python3 -c "
import os, shutil
src = '/path/to/source/folder'
files = sorted(os.listdir(src), key=lambda f: os.path.getmtime(os.path.join(src, f)))
pngs = [f for f in files if f.lower().endswith(('.png','.jpg','.jpeg','.webp'))]
for i, f in enumerate(pngs):
src_path = os.path.join(src, f)
dst = f'/tmp/vision_{i}.png'
shutil.copy2(src_path, dst)
os.system(f'sips -Z 800 {dst} --out {dst}')
print(f'{i}: {f} -> {dst}')
"
macOS Finder and screenshot tools use U+202F (narrow no-break space) instead of regular ASCII space in filenames like Screenshot 2026-04-14 at 4.05.08 PM.png. This breaks both cp and vision_analyze file path matching.
Always use Python's os.listdir() + os.path.join() to handle these. Never type or paste filenames from ls output.
import os, shutil
files = os.listdir('/path/to/folder')
for f in files:
if f.endswith('.png'):
# Use os.path.join - NOT string concatenation with typed names
full = os.path.join('/path/to/folder', f)
shutil.copy2(full, f'/tmp/clean_{i}.png')
Copy images to /tmp/ with clean ASCII names before calling vision_analyze. This avoids both the Unicode filename issue and gives the vision pipeline a simple path.
auxiliary.vision.timeout)auxiliary.vision.timeout: 240os.listdir() (handles Unicode names)/tmp/vision_0.png, /tmp/vision_1.png, etc.sips -Z 800vision_analyze tool, passing /tmp/vision_N.png paths# Step 1-3: Copy oldest 3 with clean names
python3 -c "
import os, shutil
src = '/path/to/folder'
files = sorted(
[f for f in os.listdir(src) if f.lower().endswith(('.png','.jpg','.jpeg'))],
key=lambda f: os.path.getmtime(os.path.join(src, f))
)
for i, f in enumerate(files[:3]):
shutil.copy2(os.path.join(src, f), f'/tmp/vision_{i}.png')
print(f'{i}: {repr(f)}')
"
# Step 4: Resize all
sips -Z 800 /tmp/vision_0.png --out /tmp/vision_0.png
sips -Z 800 /tmp/vision_1.png --out /tmp/vision_1.png
sips -Z 800 /tmp/vision_2.png --out /tmp/vision_2.png
Then call vision_analyze on each /tmp/vision_N.png.
| Pitfall | Symptom | Fix |
|---|---|---|
| Image too large | Timeout (>120s) | Pre-resize to 800px with sips |
| Unicode spaces in filename | "No such file or directory" or "Invalid image source" | Copy to /tmp via Python os.listdir() |
| Too many concurrent requests | GPU OOM or extreme slowdown | Process max 2 at a time |
| PNG not recognized | vision_analyze fails | Ensure file has .png extension in /tmp path |
| vision_analyze uses wrong model | Slow or bad results | Check .env AUXILIARY_VISION_* matches config.yaml |
# ~/.hermes/config.yaml
auxiliary:
vision:
provider: custom
model: qwen3.5:4b
base_url: http://localhost:11434/v1
api_key: no-key-required
timeout: 120
# ~/.hermes/.env (takes precedence over config.yaml)
AUXILIARY_VISION_PROVIDER=custom
AUXILIARY_VISION_MODEL=qwen3.5:4b
AUXILIARY_VISION_BASE_URL=http://localhost:11434/v1
AUXILIARY_VISION_API_KEY=***
Both must agree. If vision routing is wrong, check .env first -- it overrides config.yaml.