Give a text-only coding agent a pair of eyes.
Most agents run on a model that cannot look at images. When a user drops a screenshot, when a render needs checking, or when the answer is stuck inside a PNG, the agent is blind. This skill fixes that: it hands the image to the OpenAI Codex CLI, which is multimodal, and returns a written report the main model can act on.
It follows the Agent Skills format, so it works in Claude Code, Codex,
Kimi CLI, opencode, Cursor, Gemini CLI, Goose and anything else that reads SKILL.md. For a harness
that has no skill system, it still works as a plain command.
Paste this into your agent or CLI and let it do the work:
Install the codex-vision skill for me.
Clone https://github.com/fullya99/codex-vision somewhere you can keep it, read its
references/SETUP.md, and follow the section called "The install, start to finish" to the letter.
It tells you which agents to register the skill for and how to hand me the login link.
Run every command yourself, I only want to click a link. Report back with the directories you
installed into and the result of the smoke test.
That is the whole thing. The procedure lives in references/SETUP.md, so it stays correct as the skill changes and the prompt never goes stale.
git clone https://github.com/fullya99/codex-vision.git
cd codex-vision
./install.sh --link./install.sh --list shows what it found before touching anything:
agent name status directory (user scope)
claude Claude Code found ~/.claude/skills
codex Codex CLI found ~/.codex/skills
kimi Kimi CLI absent ~/.kimi/skills
opencode opencode absent ~/.config/opencode/skills
cursor Cursor absent ~/.cursor/skills
gemini Gemini CLI absent ~/.gemini/skills
goose Goose absent ~/.config/goose/skills
agents any other agent always ~/.config/agents/skills
An agent counts as found when its command is on your PATH or its config directory already exists.
The run installs for each of those, and always for ~/.config/agents/skills, the generic location
several agents fall back to when they find no directory of their own.
| Flag | What it does |
|---|---|
--list |
print the table above and stop |
--link |
symlink instead of copying, so git pull keeps every install current |
--agent kimi,cursor |
install for these only, whether or not they were detected |
--all |
install for every known agent |
--target DIR |
install into an exact directory, for a harness this list does not know |
--project [DIR] |
use the repo-local layout (.claude/skills, .codex/skills, .agents/skills) |
--no-setup |
skip the Codex CLI install and login |
Find where that tool loads skills from, usually a skills folder under its own config directory,
then point the installer at it:
./install.sh --link --target ~/.mytool/skillsAnd if it has no skill system at all, nothing is lost. The skill is a shell script with a markdown manual, so any agent that can run a command can use it:
~/.local/share/codex-vision/scripts/analyze.sh --question "what is on this screen" shot.pngPoint that agent at SKILL.md for the usage rules and it behaves the same way.
scripts/setup.sh installs the Codex CLI when it is missing. It downloads the static musl binary
matching your machine into ~/.local/bin, no sudo and no Node needed. Tested on Debian, Ubuntu and
Fedora, on x86_64 and arm64. It falls back to npm, then to Homebrew, and tells you what to do by hand
if all of that fails.
The setup script reuses an existing Codex login when there is one. Otherwise it picks in this order:
| Situation | What happens |
|---|---|
CODEX_ACCESS_TOKEN set |
codex login --with-access-token, for managed workspaces |
OPENAI_API_KEY set |
codex login --with-api-key, key piped through stdin |
| Local desktop session | codex login, the usual browser flow |
| SSH, container, CI | codex login --device-auth, code shown in the terminal |
Force one with scripts/setup.sh --auth chatgpt|device|apikey|token. A ChatGPT Plus, Pro or Business
login works fine and does not spend API credits, which is the cheapest way to run this.
When an agent runs the setup for a human, it should split the device login in two so nothing blocks in the wrong place:
scripts/setup.sh --device-async # prints the link and the code, returns immediately
scripts/setup.sh --wait-login 900 # blocks until the user has validated itThe agent calls the script itself, but it works the same by hand:
scripts/analyze.sh screenshot.png
scripts/analyze.sh --question "what does this error say" --template error crash.png
scripts/analyze.sh --complexity detailed --template ui build/home.png
scripts/analyze.sh --template diff before.png after.png
scripts/analyze.sh --json --question "list every button label" login.pngTwo complexity levels, that is the whole knob:
| Level | Model | Effort | Use it for |
|---|---|---|---|
medium (default) |
GPT-5.6 Luna | medium | reading a screen, OCR, error dialogs, quick checks |
detailed |
GPT-5.6 Sol | high | fine UI review, dense dashboards, diagrams, visual diffs |
Accounts that cannot select Sol fall back to GPT-5.6 Terra automatically, with a note on stderr.
Override anything with --model, --effort, or the CODEX_VISION_MODEL_MEDIUM and
CODEX_VISION_MODEL_DETAILED environment variables.
Templates: general, ui, ocr, diff, chart, error. They shape what the model reports.
See references/PROMPTS.md.
- bash, curl, tar, python3, and the usual coreutils
- Linux x86_64 or arm64, or macOS
- a ChatGPT login or an OpenAI API key
- images in PNG, JPEG, GIF or WebP
Run scripts/doctor.sh first. It checks the platform, the tools, the binary, the version and the
login in one shot. references/SETUP.md covers the rest: proxies, CI, custom
install paths, and the errors you are most likely to hit.
analyze.sh validates the images, picks a prompt template, then runs:
codex exec --image IMG --model MODEL -c model_reasoning_effort="EFFORT" \
--sandbox read-only --skip-git-repo-check \
--cd DIR --output-last-message OUT "PROMPT"
The final message is printed to stdout. The sandbox is read only, so the model can look but never
write. Your ~/.codex/config.toml is left alone, every setting is passed per call.
When the CLI cannot be installed at all and an API key is present, scripts/api_fallback.py posts the
image to the Responses API directly, using nothing but the Python standard library.
MIT. See LICENSE.