diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md
index 50563c97c6..a1140f1e5e 100644
--- a/docs/tool-catalog.md
+++ b/docs/tool-catalog.md
@@ -39,6 +39,7 @@ This table connects model-visible tool names to the plugin package and service s
| `@deepseek-ai/dsh-tool-todo` | `todo_write` | `ctx.tools`, `owning Agent session` | `tool/call`, `todo/write`, `tool/result` | - | todo_write is session-owned state; UIs render the latest todo/write event as a checklist. `allowParallelInProgress` is required with no default, so the catalog states its choice: `true`, whose description invites several `in_progress` items. A deployment choosing `false` receives the same tool with a description asking for exactly one active task. |
| `@deepseek-ai/dsh-tool-workflow` | `workflow` | `ctx.tools`, `ctx.workflowEngine`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents the script children)` | `tool/call`, `tool/result` | - | - |
| `@deepseek-ai/dsh-tool-web` | `web_fetch`, `web_search` | `ctx.tools`, `ctx.web`, `ctx.systemPrompt` | `tool/call`, `tool/result` | - | web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps. |
+| `@deepseek-ai/dsh-tool-image-recognition` | `recognize_image` | `ctx.tools`, `ctx.skills`, `ctx.imageRecognition`, `ctx.systemPrompt` | `tool/call`, `tool/result` | - | recognize_image keeps provider selection behind ctx.imageRecognition so the model-visible schema stays stable across backend swaps. |
@@ -1871,3 +1872,34 @@ Search the web for current information. Returns an optional summary answer and a
Source: [`packages/web/tool-web/src/index.ts`](../packages/web/tool-web/src/index.ts)
web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps.
+
+
+
+## `@deepseek-ai/dsh-tool-image-recognition`
+
+### `recognize_image`
+
+Recognize the contents of an image (objects, scenes, and text) through the configured image provider and return the recognized text.
+
+```json
+{
+ "type": "object",
+ "properties": {
+ "image": {
+ "type": "string",
+ "description": "The image to recognize: a file path, an https URL, or a data: URL."
+ },
+ "prompt": {
+ "type": "string",
+ "description": "Optional recognition focus, e.g. \"transcribe the text\" or \"describe the scene\"."
+ }
+ },
+ "required": [
+ "image"
+ ]
+}
+```
+
+Source: [`packages/vision/tool-image-recognition/src/index.ts`](../packages/vision/tool-image-recognition/src/index.ts)
+
+recognize_image keeps provider selection behind ctx.imageRecognition so the model-visible schema stays stable across backend swaps.
diff --git a/scripts/gen-tool-catalog.ts b/scripts/gen-tool-catalog.ts
index 005eb4aef9..5165434e8e 100644
--- a/scripts/gen-tool-catalog.ts
+++ b/scripts/gen-tool-catalog.ts
@@ -31,6 +31,8 @@ import PlanModeController from '@deepseek-ai/dsh-plan-mode'
import WebRuntime from '@deepseek-ai/dsh-web'
import * as WebSearchExa from '@deepseek-ai/dsh-web-search-exa'
import * as WebFetchLocal from '@deepseek-ai/dsh-web-fetch-http'
+import ImageRecognitionRuntime from '@deepseek-ai/dsh-image-recognition'
+import * as ToolImageRecognition from '@deepseek-ai/dsh-tool-image-recognition'
import SubagentRuntime from '@deepseek-ai/dsh-subagent'
import type { SubagentProvider, SubagentReportDelivery } from '@deepseek-ai/dsh-subagent'
import * as ToolSubagentControl from '@deepseek-ai/dsh-tool-subagent-control'
@@ -551,6 +553,20 @@ const TOOL_PACKAGES: ToolPackage[] = [
note:
'web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps.',
},
+ {
+ pkg: '@deepseek-ai/dsh-tool-image-recognition',
+ dir: 'tool-image-recognition',
+ source: 'packages/vision/tool-image-recognition/src/index.ts',
+ requires: ['ctx.tools', 'ctx.skills', 'ctx.imageRecognition', 'ctx.systemPrompt'],
+ writes: ['tool/call', 'tool/result'],
+ async mount(ctx) {
+ await ctx.plugin(SkillRegistry)
+ await ctx.plugin(ImageRecognitionRuntime)
+ await ctx.plugin(ToolImageRecognition)
+ },
+ note:
+ 'recognize_image keeps provider selection behind ctx.imageRecognition so the model-visible schema stays stable across backend swaps.',
+ },
]
/** One package's contribution to the catalog: its schemas plus attribution. */
diff --git a/scripts/verify-package-readme-model-experience.ts b/scripts/verify-package-readme-model-experience.ts
index d38b4743c5..4081198cf3 100644
--- a/scripts/verify-package-readme-model-experience.ts
+++ b/scripts/verify-package-readme-model-experience.ts
@@ -31,6 +31,9 @@ interface SentenceContract {
*/
const NO_MODEL_EXPERIENCE_SECTION: Readonly> = {
'packages/core/scope': 'The package is a model-agnostic registration and lifecycle primitive; model-facing consumers own any context selection.',
+ 'packages/vision/image-recognition': 'The seam is a model-agnostic provider registry; the model-facing tool and skill live in dsh-tool-image-recognition.',
+ 'packages/vision/image-recognition-http': 'The provider is a model-agnostic backend; the model-facing tool and skill live in dsh-tool-image-recognition.',
+ 'packages/bundle/image-recognition': 'The bundle mounts model-agnostic service/backend packages; the model-facing tool and skill live in dsh-tool-image-recognition.',
'packages/util/brand': 'The package is a type-only primitive erased at compile time.',
'packages/util/home-paths': 'The package only resolves harness-owned host paths; model-facing consumers own any rendered use.',
'packages/util/launch-environment': 'The package only resolves host environment values; model-facing consumers own any rendered use.',