vision-manual · diff
git:20260906.891e713 to git:20260907.f57b993
71 added, 336 removed. Audit A to A.
---
name: vision-manual
description: >
- Troubleshoot an unavailable or failed vision route without automatic
- provider/credential fallback.
- last_changed_at: 2026-08-29T00:00:00Z
+ Choose a Vision action, route, setting, or backend reference without
+ automatic provider/credential fallback.
+ last_changed_at: 2026-09-06T00:00:00Z
related_files:
- src/lingtai/tools/vision/__init__.py
- src/lingtai/tools/vision/ANATOMY.md
- src/lingtai/tools/vision/CONTRACT.md
- src/lingtai/tools/vision/BEHAVIORS.md
- src/lingtai/tools/vision/settings.py
- - src/lingtai/kernel/tool_plugin/CONTRACT.md
+ - src/lingtai/tools/vision/manual/reference/actions.md
+ - src/lingtai/tools/vision/manual/reference/routing.md
+ - src/lingtai/tools/vision/manual/reference/settings.md
+ - src/lingtai/tools/vision/manual/reference/backends.md
maintenance: |
- Keep this manual provider-neutral and the settings action read-only. Keep each
- projected comment pointer aligned with its exact Setting heading. It must not
- import, expose, or link to a TUI package, credential value, endpoint secret,
- or automatic MCP action.
+ Keep this page a short provider-neutral router and the settings action
+ read-only. Keep every setting anchor stable and route depth to the focused
+ references. Do not add provider, credential, endpoint, CLI, or MCP fallback;
+ never import, expose, or link a secret.
---
# Vision manual
- This is the provider-neutral fallback for `vision`. It contains guidance only;
- it does not discover, install, start, or invoke a backend. The static official
- Vision declaration owns this package as its `manual="vision"` destination, so
- the registrar-bound `manual` action reads this installed `SKILL.md` and not a
- host-global or another family's skill.
+ This installed, provider-neutral manual is guidance only. The static declaration
+ owns its `manual="vision"` destination; the reserved action reads this body and
+ path, not a host-global or another family's skill. It does not discover, install,
+ start, or invoke a backend.
- ## Call shape
+ ## Choose an action
- `vision` is one action-separated tool with five strict actions:
+ `vision` has one strict action-separated root. Every call requires
+ `action`, `input`, and `reasoning`; `input` must match the selected child. Use
+ these first-call forms:
- - `vision(action="analyze", input={"image_path": "...", "question": null},
- reasoning="...")` — the direct image request. `image_path` and nullable
- `question` are required fields; `null` selects the default prompt
- `Describe what you see in this image.`. The optional nullable `preset` field
- explicitly borrows one allowed preset's vision service for this call.
- - `vision(action="check", input={"preset": null}, reasoning="...")` — resolve
- the default route without an image. The `preset` field is required and must
- be `null` or an allowed preset reference. A non-null value resolves the
- borrowed provider/model and constructs its service, but never calls a
- provider or sends image data.
- - `vision(action="list", input={}, reasoning="...")` — mechanically enumerate
- the active route and vision-capable presets in `manifest.preset.allowed`.
- It reads route declarations only: it constructs no provider service and
- reads no credential.
- - `vision(action="settings", input={}, reasoning="...")` — show the applied
- bind-time configuration as rows containing exactly `key`, `current`,
- `default`, `configurable`, and `comment`. Input is strictly `{}`. This action
- never sets, resets, validates, re-reads, or writes configuration. Follow each
- row's exact `comment` section below for meaning and the owner procedure.
- - `vision(action="manual", input={}, reasoning="...")` — this guidance. Its
- input is strictly empty; it reads the installed manual body/path and performs
- no config, credential, provider, image, or analyze operation.
+ - **Analyze an image:**
+ `vision(action="analyze", input={"image_path": "...", "question": null}, reasoning="...")`.
+ `image_path` is required; a relative path is resolved from the workdir.
+ `question: null` means `Describe what you see in this image.`. Add
+ `preset: "<allowed reference>"` only to explicitly borrow a route listed in
+ `manifest.preset.allowed`.
+ - **Check a route:**
+ `vision(action="check", input={"preset": null}, reasoning="...")`.
+ `null` checks the default route; a reference checks that explicitly borrowed
+ route without sending an image.
+ - **List routes:** `vision(action="list", input={}, reasoning="...")`.
+ This mechanically lists the active route and vision-capable allowed presets;
+ it constructs no provider service or credential.
+ - **Show applied settings:**
+ `vision(action="settings", input={}, reasoning="...")`. This is SHOW-only:
+ it does not read, validate, set, reset, or write configuration.
+ - **Load guidance:** `vision(action="manual", input={}, reasoning="...")`.
- `reasoning` is required on every action and is invocation metadata; it never
- becomes part of child input. Optional `summarize` is a root presentation
- control. An unknown action, root field, or cross-action input field is rejected
- before provider, credential, image, or manual-child work.
+ Unknown actions, root fields, or cross-action input fields fail before provider,
+ credential, image, or manual-child work. `preset` is an explicit authorization
+ boundary, not fallback: the allowed preset's own provider/model/credential
+ identity is used for that request. A default failure remains a sanitized error;
+ Vision never automatically switches provider/model/credential, preset, MCP, or
+ CLI, and Vision never auto-invokes MCP. Alternatives are instructions for a
+ later explicit operator action.
- ## Settings inventory
+ For action details and result shapes, read
+ [actions](reference/actions.md). For route identity, borrowing, Claude CLI,
+ active-preset guidance, and safety, read [routing](reference/routing.md). For
+ local servers, MLX, setup, and troubleshooting, read
+ [backends](reference/backends.md).
- The inventory freezes the effective values used when Vision binds during boot
- or `system(action="refresh", input={}, reasoning="apply approved Vision config")`.
- SHOW does not re-read a file, environment variable, preset, or provider. If the
- provider or required model is not truthfully available, the local owner file is
- invalid, or an opaque injected service has no attributable owner route, the
- whole action returns `SETTINGS_UNAVAILABLE`; it never fabricates or emits
- partial rows. `configurable: true` means an existing owner procedure can change
- the value outside SHOW, not that this action can mutate anything.
+ ## Settings anchors
- Each setting below names its own source and precedence because the routes do
- not share one universal chain. Every real change requires owner authorization,
- an edit through the named file/config/preset procedure, refresh or relaunch as
- stated, and a second SHOW to verify the newly applied snapshot.
+ The settings action returns exactly `key`, `current`, `default`,
+ `configurable`, and `comment` for the applied bind snapshot. Sensitive values
+ and path-like models are redacted. SHOW never mutates or re-reads state. Each
+ anchor below is stable; read the [settings reference](reference/settings.md)
+ for source, precedence, redaction, and the existing owner procedure.
## Setting: provider
- The current direct-route provider. It comes from the explicit Vision capability
- or, when compatible, the active provider. There is no provider default and no
- automatic provider switch. Change `manifest.capabilities.vision.provider` in
- the active `init.json`/preset, then refresh. Routing changes do not grant
- credentials, installation, or network authority.
+ The current direct-route provider; no provider default or automatic switch.
## Setting: base-url
- The effective endpoint override. It comes from the explicit Vision capability,
- the same-provider active route, or — for `provider="local"` —
- `settings/vision.json` and then `http://localhost:11434/v1`. MiMo and Codex
- services also have their constructor endpoints. The value is sensitive and
- always redacted. Edit the existing capability/preset or local owner file,
- refresh, and SHOW again; never paste a private endpoint into logs or chat.
+ The bound endpoint override or route-owned endpoint; sensitive values are redacted.
## Setting: model
- The model identifier used by the bound route. It comes from the explicit Vision
- capability, the same-provider active route, the local owner file, or the
- successfully constructed service. Public identifiers are shown exactly; a
- path-like model value is private, so SHOW redacts both current and default.
- Local Vision has no model default. Only the explicit MLX route has a
- Vision-owned model default. Change the active capability/preset or local owner
- file, ensure any model pull/install has separate human approval, refresh, and
- verify with SHOW.
+ The bound route model; path-like values are redacted and no hidden local model is assumed.
## Setting: api-key
- Whether API credential material was applied. The resolved value comes from an
- explicit capability `api_key_env`/`api_key`, the same-provider credential, or
- the local owner file; local Vision otherwise uses a non-secret SDK placeholder.
- Codex and MLX do not consume this field. Current and default are always
- redacted—SHOW retains only presence, never raw material. Change the owner secret
- store or launcher configuration, then relaunch or refresh without printing it.
+ Whether the bound route applied credential material; raw values are never shown.
## Setting: api-key-env
- Whether an explicit capability credential-variable pointer was applied. The
- pointer is resolved once during bind before raw-key fallback. Its name and value
- are both sensitive and redacted; there is no default. Change
- `manifest.capabilities.vision.api_key_env` and the launcher/secret-manager
- environment through their existing owner procedures, then relaunch or refresh.
- SHOW never reads or changes the process environment.
+ Whether an explicit credential-variable pointer was applied; SHOW never reads the environment.
## Setting: max-tokens
- The direct service's positive response-token cap. An explicit capability value
- wins; local Vision next reads `settings/vision.json`. OpenAI-compatible,
- Anthropic-compatible, MiMo, and local services default to `1024`; MLX defaults
- to `512`; routes that do not consume this field show `null`. Edit the existing
- capability/preset or local owner file, refresh, and verify with SHOW.
+ The route's response-token cap where supported; route defaults remain owner-defined.
## Setting: api-compat
- The compatibility family selected from explicit Vision configuration or the
- same active provider's defaults. Accepted values are `openai` or `anthropic`
- where the relay supports that protocol. There is no default and an irrelevant
- route shows `null`. Change the owning capability/provider configuration,
- refresh, run `check`, and verify with SHOW. It does not grant provider access.
+ The route compatibility family where applicable; it grants no provider access.
## Setting: wire-api
- The effective OpenAI-compatible wire. Accepted configuration values are
- `auto`, `chat_completions`, or `responses`; route support still decides whether
- construction succeeds. Local/OpenAI-compatible services normally resolve to
- `chat_completions`, while Codex is `responses`; non-applicable routes show
- `null`. Change the owning capability or same-provider configuration, refresh,
- run `check`, and verify with SHOW.
+ The configured compatible wire where applicable; route support still controls construction.
## Setting: default-headers
- Whether provider-owned HTTP headers were applied to a compatible service.
- Explicit Vision headers precede same-provider defaults. The complete mapping,
- including header names, is sensitive and always redacted; no headers is the
- `null` default. Edit the owning capability/provider configuration, refresh, and
- SHOW again without logging the mapping.
+ Whether provider-owned headers were applied; the mapping is always redacted.
## Setting: token-path
- Whether a Codex OAuth identity path was applied. It comes from an explicit
- Vision value, the same provider's `codex_auth_path`, or authorized pool
- selection. Non-Codex routes show `null`. The path and token material are
- sensitive and always redacted. Use the existing Codex login/account-pool or
- preset procedure, then refresh and SHOW; never copy the file or token to output.
+ Whether a Codex OAuth identity path was applied; path and token material are redacted.
## Setting: instructions
- Whether Codex Responses instructions were applied. Explicit Vision
- instructions win; the Codex service otherwise owns its concise-assistant
- default. Non-Codex routes show `null`. The text is sensitive and always
- redacted. Edit the active capability/preset, refresh, and SHOW again; never put
- credentials or authorization in instructions.
+ Whether Codex Responses instructions were applied; instruction text is redacted.
## Setting: max-output-tokens
- The optional Codex Responses output cap. Accepted values are positive integers
- supported by the backend, or `null` to omit it; the default is `null`. Change
- the active capability/preset only after validating backend support, refresh,
- run `check`, and verify with SHOW. This is distinct from `max_tokens`.
+ The optional Codex Responses output cap, distinct from `max_tokens`.
## Setting: timeout
- The Codex request timeout in positive finite seconds. An explicit capability
- value wins; Codex defaults to `120.0`, and non-Codex routes show `null`. Change
- the active capability/preset, refresh, and verify with SHOW. A larger timeout
- changes wait tolerance only; it grants no network, provider, or retry authority.
-
- ## Route behavior and failures
-
- `vision` is always registered. With no explicit provider or `preset`, the default
- route follows the active provider's own compatible identity (model, endpoint,
- wire, and credential) or an explicitly configured Vision service. Missing or
- unsupported identity fails closed to manual guidance. There is no hidden model,
- legacy credential, provider switch, or automatic MCP/provider fallback.
-
- An explicit `preset` request is different from fallback. The reference must be
- listed in `manifest.preset.allowed`; Vision then loads that preset read-only and
- uses the allowed preset's own `manifest.llm` and `manifest.capabilities.vision`
- identity. That can include resolving the allowed preset's own `api_key` or
- `api_key_env`, or selecting its own Codex OAuth-pool identity, in order to build
- the requested borrowed service. Borrowing is therefore authorized credential
- routing for one call: it does not switch the active preset, lend the active
- preset's model/credential to the borrowed route, or silently choose another
- preset after a failure. An unlisted, unreadable, or incomplete preset fails
- closed with sanitized guidance.
-
- A direct setup or request failure reports the failure type and points here for
- explicit alternatives; it never exposes exception contents. A mention of MCP,
- a local server, another preset, or the Claude CLI is an instruction for a later
- explicit operator/agent action, not an automatic fallback or invocation.
-
- ## Borrow flow
-
- To use another already-authorized preset's vision service for one image request:
-
- 1. Run `vision(action="list", input={}, reasoning="...")` to see which allowed
- preset declarations advertise vision and their endpoint classification.
- 2. Run `vision(action="check", input={"preset": "<allowed preset>"},
- reasoning="...")` to resolve that preset's provider/model without sending
- an image. Route construction may resolve that preset's own credential.
- 3. Run `vision(action="analyze",
- input={"image_path": "...", "question": null,
- "preset": "<allowed preset>"}, reasoning="...")` to send one image request
- through the explicitly selected service.
-
- The allowed list is the authorization boundary. Borrowing never silently
- switches the active preset and never auto-invokes MCP or another provider. If
- the selected route fails, inspect the returned manual guidance and ask the
- operator before changing configuration, preset authorization, or installing a
- backend.
-
- ## Claude backend: use the Claude CLI for vision
-
- When the active provider is a Claude-family backend (`claude-code`, `claude_code`,
- or the `claude-p` vision alias), the vision capability does not proxy Claude's
- own CLI authentication. The analyze call fails closed with explicit guidance
- instead of constructing a service:
-
- > You are using claude as backend, therefore to use vision run `claude -p`;
- > see the vision manual for more details.
-
- ### How Claude CLI vision works
-
- Claude Code attaches images by file path: when the prompt references an image
- path, the CLI reads the file and sends it to the model as an image input block
- alongside the text. `-p` / `--print` is the non-interactive print mode, so the
- analysis is returned as plain text on stdout — ideal for scripting.
-
- - Run in print mode with the image path referenced in the prompt:
- `claude -p "Analyze this image: /path/to/image.png"`.
- - Supported image formats include JPEG, PNG, and GIF (GIF uses the first
- frame). The CLI uses its own authentication (claude.ai subscription, API
- key, or a configured provider) and its own cost model.
-
- ### Progressive disclosure to the official docs
-
- For authoritative details, progressively read the Claude Code CLI documentation:
-
- - CLI reference: <https://code.claude.com/docs/en/cli-reference>
- - Image workflows: <https://code.claude.com/docs/en/common-workflows>
-
- This manual never auto-invokes the CLI; running `claude -p` is an explicit
- operator/agent action with the CLI's own auth and cost model.
-
- ## Stay on the active preset
-
- Inspect the identity already shown in the prompt: the current provider, model,
- and sanitized endpoint. The default route follows that active LLM; do not
- substitute another provider, model, credential, endpoint, or wire protocol, and
- never silently switch or auto-invoke an MCP. If the active route cannot see
- images, the call fails explicitly. Use a borrowed route only by naming an
- already-authorized preset in the `preset` field; its own credential may be
- resolved for that explicit request.
-
- ## Find the current preset's method
-
- Use the `skills` capability's catalog to search installed skills for a manual
- matching that provider/model or preset. Read the matching manual before trying
- its documented method or official-page pointer. If no matching manual is
- present, report that no discoverable vision method is available.
-
- An optional MCP or other skill may be described by that preset manual, but it is
- always an explicit operator/agent action. This manual never auto-loads or
- auto-invokes MCP.
-
- ## Safety
-
- Never request or print API keys, OAuth tokens, environment values, headers, or
- full unsanitized URLs. Missing provider, model, or endpoint fields are simply
- unknown; do not fill them with guesses.
-
- ## Local vision (generic OpenAI-compatible provider)
-
- `provider="local"` points the `vision` capability at any local
- OpenAI-compatible vision server (Ollama, LM Studio, vLLM, llama.cpp server, ...)
- by URL. It needs no API key (a placeholder is synthesized; local servers ignore
- it), defaults `base_url` to `http://localhost:11434/v1`, and requires an
- explicit `model` - there is no hidden default model, because a silently assumed
- model masks misconfiguration.
-
- The endpoint is operator-owned. Configure it in `settings/vision.json` (the
- family-owned file, like `settings/web.json`), in the capability manifest, or
- both (capability kwargs override the file).
-
- ### 1. Pick and install a server + pull a vision model
-
- Any server that speaks the OpenAI Chat Completions API with image support
- works. Examples:
-
- - **Ollama** (easiest): install from <https://ollama.com>, then pull a
- vision-capable model. `moondream` is a good small default (~1.7 GB, runs on
- CPU or a small GPU, fine for OCR and basic description):
-
- ollama pull moondream
-
- Other vision-capable Ollama models exist (`llava`, `qwen2.5vl`, ...). The
- model must be a vision model - a text-only model fails at request time with a
- "does not support images" style error.
-
- - **LM Studio**: start a local server with an image-capable model, note the
- port (default `http://localhost:1234/v1`).
- - **vLLM / llama.cpp server**: serve a multimodal model and point `base_url` at
- its `/v1` endpoint.
-
- ### 2. Configure the endpoint
-
- Two equivalent owner procedures are available; capability input wins over the
- file. The public settings action only shows the bound result.
-
- **`settings/vision.json`** (agent working dir, applies on next refresh):
-
- {
- "schema_version": 1,
- "base_url": "http://localhost:11434/v1",
- "model": "moondream",
- "max_tokens": 1024
- }
-
- `api_key` is optional and omitted here. Only `schema_version` plus the
- documented fields are allowed; an invalid file is a hard setup error surfaced
- as manual guidance.
-
- **Capability manifest** (`init.json` or the active preset's
- `manifest.capabilities`):
-
- "vision": {
- "provider": "local",
- "model": "moondream"
- }
-
- "vision": {
- "provider": "local",
- "model": "moondream",
- "base_url": "http://localhost:11434/v1",
- "max_tokens": 1024
- }
-
- `model` is required and must name a model the server actually serves. `base_url`
- defaults to `http://localhost:11434/v1`; change it when the server runs on a
- non-default port (the `/v1` OpenAI-compatible suffix is required). `api_key` is
- optional - local servers ignore it, so a placeholder is synthesized.
-
- > **Preset note.** `vision` is always registered; an explicit `capabilities.vision`
- > entry is **not** required to make the tool appear. The default route inherits
- > the active LLM's own Responses API. A capability-manifest entry (in
- > `init.json` or the active preset) is only needed to override that default,
- > e.g. to point at `provider="local"`. To borrow another preset's vision
- > service for a single call, list that preset in `manifest.preset.allowed` and
- > pass `preset` on the analyze call; no `capabilities.vision` edit is needed.
-
- ### 3. Use it
-
- After configuring and refreshing, the `vision` tool is available:
-
- vision(action="analyze", input={"image_path": "/path/to/image.png", "question": null}, reasoning="...")
-
- A successful call returns `{"status": "ok", "analysis": "..."}`. If you get a
- sanitized setup failure instead, check the troubleshooting table below.
-
- ### 4. Troubleshooting local vision
-
- | Symptom | Likely cause / fix |
- |---|---|
- | "No direct vision provider was configured" | No explicit provider and no usable active-LLM route. The tool is always registered; either borrow an allowed preset's vision service via the `preset` option, or configure a local route (see below), then refresh. |
- | "Local vision needs an explicit model" | No `model` is set in `settings/vision.json` or the capability manifest. Set `model` to a pulled/served vision model name, then refresh. |
- | "Local vision settings are invalid" | `settings/vision.json` has an unknown field, bad type, or a schema_version other than 1. Fix the file and refresh. |
- | Connection refused on the endpoint | The local server is not running. Start it (`ollama serve` or the desktop app) and retry. |
- | "model '<name>' not found" | The model was never pulled or has a different name. Run `ollama list` (or your server's model list) and set `model` to the exact name. |
- | "does not support images" / vision request rejected | The configured model is text-only. Pull/serve a vision model (e.g. `moondream`) and point `model` at it. |
- | "...missing the '/v1' suffix..." (from the service) | `base_url` is missing the OpenAI-compatible suffix. Use e.g. `http://localhost:11434/v1`. |
- | HTML/JSON parse failure on the response | The server returned a non-ChatCompletion body - usually the route is wrong (see previous row) or the server is too old. Upgrade and use `/v1`. |
- | GPU not used / slow | The server offloads to the GPU only when the model fits VRAM. `moondream` fits most GPUs; larger models fall back to CPU. |
-
- ### 5. Apple MLX (macOS only)
+ The Codex request timeout where applicable; changing it grants no retry or network authority.
- The native on-device MLX pseudo-provider (`provider="mlx"`) is available as an
- explicit opt-in for Apple Silicon. It is not advertised in check-caps; pass
- `model` (an `mlx-community/...` vision model) and `max_tokens`. It requires no
- API key.
+ If a route, local settings document, model, or credential is unavailable, the
+ whole settings inventory fails closed rather than returning partial or guessed
+ rows. To change a value, use its existing owner procedure, refresh or relaunch,
+ and then SHOW again; this manual never performs that change.