Docs文档

Providers

ModLens does not depend on any single vision service. Ten sources of vision in total: six built-in providers, any one of which is enough, plus four local agent CLIs whose logins can be reused.

Built-in providers

Provider What it needs Speed per read Good for
gemini-api a free Gemini API key (3 minutes, no card) 5-10s the recommended default
openai any OpenAI-compatible endpoint (key + baseUrl + model) 5-10s qwen-vl, GLM, self-hosted gateways
anthropic an Anthropic API key 5-10s machines already holding one
antigravity-cli the free agy CLI, one browser sign-in, no key 15-45s zero-signup starts
claude-cli a signed-in Claude Code 20-45s riding your existing Claude subscription
kimi-cli a signed-in Kimi Code 20-45s riding your existing Kimi subscription, named explicitly

kimi-cli runs only when named, never as a silent failover peer. Default with nothing configured: antigravity-cli.

Failover

Without a pinned provider, every configured engine forms one failover chain: configured API providers first (5-10s), then the agent CLIs (15-45s). The first good result wins, and meta.attempts records every attempt so a fallback is never silent.

modlens config set provider <name> states a preference (the chain still backs it up). -p <name> pins exactly one with no fallback.

openai is a universal socket, not just OpenAI

Any endpoint speaking the OpenAI chat-completions protocol with image input plugs straight in. That covers most of the vision-model world:

modlens config set openai.baseUrl https://dashscope.aliyuncs.com/compatible-mode/v1   # qwen-vl
modlens config set openai.apiKey  <key>
modlens config set openai.model   qwen3-vl-plus

apiKey (and the matching env var) also accepts a comma-separated list. ModLens rotates to the next key after authentication, rate-limit, or quota failures. Network, 5xx, and parse failures skip remaining keys and keep provider failover.

The same three keys work for GLM’s open platform, SiliconFlow, OpenRouter, a self-hosted vLLM/Ollama, or any gateway of your own.

Reusing what your machine already has

Two more sources of vision need zero new keys, each behind one explicit consent recorded in config:

  • The harness you are talking in right now. Running inside Claude Code with a subscription signed in? claude-cli reads images through it out of the box. The install flow asks the same question for whichever harness you install into.
  • Every other agent CLI on the machine. modlens doctor discovers them, you grant per harness, and they join the same failover chain with no priority over your own keys. Every reused read is labeled in meta.warnings with whose quota it spent, so nothing is ever silently billed:
Reused CLI What it needs Grant with Rides as
Codex a signed-in Codex CLI with a vision model config set reuse.codex true agent lane, 15-45s
OpenCode a vision model configured in OpenCode config set reuse.opencode true agent lane, 15-45s
Pi model credentials held by Pi config set reuse.pi true an API key upgrades to the 5-10s inline lane, OAuth drives Pi itself
Grok a signed-in Grok CLI (SuperGrok) config set reuse.grok true agent lane, 15-45s

Machines behind a proxy set HTTPS_PROXY or modlens config set proxy <url> and the API providers route through it.

Provider setup recipes

antigravity-cli (default, free, no key)

Needs Antigravity CLI installed and signed in:

curl -fsSL https://antigravity.google/cli/install.sh | bash
agy    # user must complete browser sign-in themselves, then exit

Any free Google account works; no Google AI Pro needed. Sign-in cannot be automated, ask the user to run agy once.

gemini-api (free key, fastest free route, 5-10s)

  1. The user creates a key at https://aistudio.google.com (three minutes, no credit card, free tier does not expire).
  2. Store it either way:
modlens config set gemini-api.apiKey <key>
# value omitted: a hidden prompt, so the key skips argv, shell history, and this chat
modlens config set gemini-api.apiKey

Offer the hidden prompt first when the user is at their own terminal. Most users paste the key into the chat because it is convenient, and that works too: take it and store it. The prompt is for the ones who would rather not.

Default model gemini-3.6-flash has vision on the free tier (about 10-15 requests/min, 1500/day). Free-tier data may be used by Google to improve products; mention this if the user handles sensitive images.

openai (any OpenAI-compatible multimodal endpoint)

Needs three values. Example for DashScope qwen:

modlens config set openai.baseUrl https://dashscope.aliyuncs.com/compatible-mode/v1
modlens config set openai.apiKey <sk-key>
modlens config set openai.model qwen3.6-27b

baseUrl is required, official OpenAI included (https://api.openai.com/v1): this route serves any compatible endpoint, and guessing one would send a key meant for another vendor, and the image beside it, somewhere the user never named. The model must be multimodal; text-only models will fail or hallucinate.

This route enforces nothing server-side by default, so a weaker model can answer with half the contract and the run fails with an explicit error. If that happens, ask the gateway to enforce it:

modlens config set openai.structuredOutput true

The contract goes out as response_format: json_schema in strict form, derived from the schema modlens checks against. Off by default because a gateway without structured-output support answers 400 for the field, so turn it back off if the endpoint refuses it. Turning thinking off (below) makes the shape failures more likely, so the two often go together.

anthropic (Claude API key)

modlens config set anthropic.apiKey <sk-ant-key>

Default model is Claude Haiku (claude-haiku-4-5-20251001). Schema is enforced through a forced tool call.

The ANTHROPIC_BASE_URL trap is defused. modlens used to bind that variable to anthropic.baseUrl field by field, so a shell that routed Claude Code through a text-only gateway silently sent vision requests there too, even beside a key set in the config file. The moment the file names anthropic, the file is this route’s whole source and that variable no longer reaches it: set anthropic.baseUrl when you do want a different endpoint. ANTHROPIC_API_KEY and ANTHROPIC_BASE_URL still configure this route on their own while the file says nothing about anthropic, both halves coming from the same place. A run caught between the two, with the variable set and the file naming anthropic without a baseUrl, refuses and prints the command that keeps the endpoint you were using.

kimi-cli (Kimi Code login, no key)

Rides an existing kimi sign-in, so it spends the user’s Kimi Code subscription rather than a key. Install from https://moonshotai.github.io/kimi-code/, run kimi once and /login, then:

modlens config set provider kimi-cli
modlens config set kimi-cli.model <alias>   # optional; kimi's own default otherwise

Naming it is what turns it on. Unlike the other CLI routes it never joins the failover chain on its own, because it spends a subscription and installing the CLI is not agreement to spend it.

The model alias is kimi’s, in <provider>/<model> form as kimi provider list shows it, and it has to accept image input. This route enforces no schema (the CLI has no --json-schema), so the contract travels as a filled-in JSON template and a weaker model can answer with half of it; -p gemini-api is the fallback when that happens.

One implementation note worth knowing if you debug it: modlens runs kimi with skill discovery pointed at an empty directory. Otherwise kimi can find the modlens skill in the shared skill directories and read the image by calling modlens, which is modlens calling itself.

claude-cli (Claude Code login, no key)

Rides an existing claude sign-in, so it costs the user’s Claude subscription quota, not a separate API bill. Requires Claude Code installed and logged in (claude --version to check). Runs with --allowedTools Read only. Local image files only; for remote URLs use gemini-api instead. Default model alias haiku.

modlens config set provider claude-cli   # make it the default if the user wants

Every config key is in Configuration. Flags and default models are in the CLI manual. Remote URL fetching is in Security.