diff --git a/apps/docs/.vitepress/config.mts b/apps/docs/.vitepress/config.mts index 585c20a9..2c1e8212 100644 --- a/apps/docs/.vitepress/config.mts +++ b/apps/docs/.vitepress/config.mts @@ -66,8 +66,8 @@ export default defineConfig({ - Base URL: \`http://localhost:1349\` - Auth: Session token via \`POST /api/auth/login\` or API key (\`Authorization: Bearer si_...\`) -- Tools: \`POST /api/v1/tools/{toolId}\` (multipart: file + settings JSON) -- Batch: \`POST /api/v1/tools/{toolId}/batch\` (multiple files, returns ZIP) +- Tools: \`POST /api/v1/tools/{section}/{toolId}\` (multipart: file + settings JSON) +- Batch: \`POST /api/v1/tools/{section}/{toolId}/batch\` (multiple files, returns ZIP) - Pipelines: \`POST /api/v1/pipeline/execute\` (chain tools sequentially) - Interactive API docs on running instance: \`/api/docs\` - OpenAPI spec on running instance: \`/api/v1/openapi.yaml\` diff --git a/apps/landing/src/components/FeatureHighlights.astro b/apps/landing/src/components/FeatureHighlights.astro index 639e228a..67527789 100644 --- a/apps/landing/src/components/FeatureHighlights.astro +++ b/apps/landing/src/components/FeatureHighlights.astro @@ -119,7 +119,7 @@ const aiPillColors = [
# Resize an image via the API
-$ curl -X POST localhost:1349/api/v1/tools/resize \
+$ curl -X POST localhost:1349/api/v1/tools/image/resize \
   -F "file=@photo.jpg" \
   -F 'settings={"width":800}'
 
diff --git a/llms.txt b/llms.txt
index 125df908..89e07dfd 100644
--- a/llms.txt
+++ b/llms.txt
@@ -216,7 +216,7 @@ Authentication methods:
 API keys support scoped permissions that intersect with user role permissions.
 
 Processing a file:
-  POST /api/v1/tools/:toolId
+  POST /api/v1/tools/:section/:toolId
   Content-Type: multipart/form-data
   Body: file (binary), settings (JSON string)
   Response: { jobId, downloadUrl, originalSize, processedSize }
@@ -231,7 +231,7 @@ Pipelines (chained tool workflows):
   DELETE /api/v1/pipeline/:id
   POST /api/v1/pipeline/batch
 
-Batch processing: POST /api/v1/tools/:toolId/batch (multiple files in, ZIP archive out).
+Batch processing: POST /api/v1/tools/:section/:toolId/batch (multiple files in, ZIP archive out).
 
 ## Tech Stack
 
diff --git a/scripts/lib/rewrite-tool-paths.ts b/scripts/lib/rewrite-tool-paths.ts
index 9a970b81..e3e957d3 100644
--- a/scripts/lib/rewrite-tool-paths.ts
+++ b/scripts/lib/rewrite-tool-paths.ts
@@ -5,7 +5,7 @@ export type IdToSection = Record;
 // next char is "-"). ":" lets YAML path keys match (".../resize:"); the backtick
 // lets backtick string literals match. ":toolId"/"{toolId}" placeholders never
 // appear as real ids in the map, so parametric routes are left untouched.
-const BOUNDARY = "(?=$|[/\"'`\\s?#:])";
+const BOUNDARY = "(?=$|[/\"'`\\s?#:,)])";
 
 function escapeRegExp(s: string): string {
   return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
diff --git a/tests/benchmark/bench-ai.sh b/tests/benchmark/bench-ai.sh
index d9dc801e..11e308ff 100755
--- a/tests/benchmark/bench-ai.sh
+++ b/tests/benchmark/bench-ai.sh
@@ -150,7 +150,7 @@ for batch_size in 3 5; do
   output_file=$(mktemp)
   cid=$(get_container_id)
 
-  curl_args=(-s -X POST "${BASE_URL}/api/v1/tools/remove-background" -H "Authorization: Bearer ${TOKEN}")
+  curl_args=(-s -X POST "${BASE_URL}/api/v1/tools/image/remove-background" -H "Authorization: Bearer ${TOKEN}")
   for i in $(seq 1 "$batch_size"); do
     curl_args+=(-F "file=@${P}")
   done
diff --git a/tests/benchmark/bench-limits.sh b/tests/benchmark/bench-limits.sh
index 6bc5a4f9..3e41e723 100755
--- a/tests/benchmark/bench-limits.sh
+++ b/tests/benchmark/bench-limits.sh
@@ -90,7 +90,7 @@ run_batch_bench() {
 
   output_file=$(mktemp)
 
-  local curl_args=(-s --max-time 180 -X POST "${BASE_URL}/api/v1/tools/resize")
+  local curl_args=(-s --max-time 180 -X POST "${BASE_URL}/api/v1/tools/image/resize")
 
   for i in $(seq 1 "$count"); do
     curl_args+=(-F "file=@${F}/test-200x150.png")
diff --git a/tests/benchmark/bench.sh b/tests/benchmark/bench.sh
index f76b5bd5..5dc667cf 100755
--- a/tests/benchmark/bench.sh
+++ b/tests/benchmark/bench.sh
@@ -277,7 +277,7 @@ for concurrency in 1 3 5 10 20; do
 
   for i in $(seq 1 "$concurrency"); do
     (
-      result=$(curl -s -X POST "${BASE_URL}/api/v1/tools/resize" \
+      result=$(curl -s -X POST "${BASE_URL}/api/v1/tools/image/resize" \
         -H "Authorization: Bearer ${TOKEN}" \
         -F "file=@${L}" \
         -F 'settings={"width":800}' \
diff --git a/tests/integration/ai-canvas-expand.test.ts b/tests/integration/ai-canvas-expand.test.ts
index 20f918f6..5b717237 100644
--- a/tests/integration/ai-canvas-expand.test.ts
+++ b/tests/integration/ai-canvas-expand.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the ai-canvas-expand AI tool (/api/v1/tools/ai-canvas-expand).
+ * Integration tests for the ai-canvas-expand AI tool (/api/v1/tools/image/ai-canvas-expand).
  *
  * This tool uses async processing: valid requests return 202 with a jobId,
  * and the result is delivered via SSE. The Python sidecar is not available
diff --git a/tests/integration/api.test.ts b/tests/integration/api.test.ts
index 863e040c..ab46d46f 100644
--- a/tests/integration/api.test.ts
+++ b/tests/integration/api.test.ts
@@ -2896,7 +2896,7 @@ describe("OCR API", () => {
 // BATCH PROCESSING
 // ═══════════════════════════════════════════════════════════════════════════
 describe("Batch processing", () => {
-  describe("POST /api/v1/tools/:toolId/batch", () => {
+  describe("POST /api/v1/tools/:section/:toolId/batch", () => {
     it("processes multiple images in a batch and returns ZIP", async () => {
       const { body: payload, contentType } = createMultipartPayload([
         { name: "file", filename: "a.png", contentType: "image/png", content: PNG_1x1 },
diff --git a/tests/integration/auto-subtitles.test.ts b/tests/integration/auto-subtitles.test.ts
index 568e6c32..196a8140 100644
--- a/tests/integration/auto-subtitles.test.ts
+++ b/tests/integration/auto-subtitles.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the auto-subtitles tool (/api/v1/tools/auto-subtitles).
+ * Integration tests for the auto-subtitles tool (/api/v1/tools/video/auto-subtitles).
  *
  * The transcription bundle (faster-whisper) is not installed locally, so the
  * 501 gate is always hit. Validation paths (bad settings) fire after the 501
diff --git a/tests/integration/background-replace.test.ts b/tests/integration/background-replace.test.ts
index 086d2397..730bf621 100644
--- a/tests/integration/background-replace.test.ts
+++ b/tests/integration/background-replace.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the background-replace tool (/api/v1/tools/background-replace).
+ * Integration tests for the background-replace tool (/api/v1/tools/image/background-replace).
  *
  * This tool reuses the rembg bundle (background-removal). The 501 gate fires
  * before any settings validation when the bundle is absent. Locally and in CI,
diff --git a/tests/integration/barcode-generate.test.ts b/tests/integration/barcode-generate.test.ts
index 3f828388..1fac2f56 100644
--- a/tests/integration/barcode-generate.test.ts
+++ b/tests/integration/barcode-generate.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the barcode-generate tool (/api/v1/tools/barcode-generate).
+ * Integration tests for the barcode-generate tool (/api/v1/tools/image/barcode-generate).
  *
  * Custom JSON POST route mirroring qr-generate. Generates barcode images
  * from text input using bwip-js. Tests cover code128, ean13 validation,
diff --git a/tests/integration/barcode-read.test.ts b/tests/integration/barcode-read.test.ts
index ab9db961..913a10da 100644
--- a/tests/integration/barcode-read.test.ts
+++ b/tests/integration/barcode-read.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the barcode-read tool (/api/v1/tools/barcode-read).
+ * Integration tests for the barcode-read tool (/api/v1/tools/image/barcode-read).
  *
  * Covers barcode/QR code detection from images, annotated image generation,
  * graceful handling of images without barcodes, and input validation.
diff --git a/tests/integration/beautify.test.ts b/tests/integration/beautify.test.ts
index d80cab26..9828ef53 100644
--- a/tests/integration/beautify.test.ts
+++ b/tests/integration/beautify.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the beautify tool (/api/v1/tools/beautify).
+ * Integration tests for the beautify tool (/api/v1/tools/image/beautify).
  *
  * Beautify adds polished backgrounds, shadows, device frames, watermarks,
  * and social media sizing to screenshots. Tests exercise all background types,
diff --git a/tests/integration/blur-background.test.ts b/tests/integration/blur-background.test.ts
index 13678a50..1a4b8ce7 100644
--- a/tests/integration/blur-background.test.ts
+++ b/tests/integration/blur-background.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the blur-background tool (/api/v1/tools/blur-background).
+ * Integration tests for the blur-background tool (/api/v1/tools/image/blur-background).
  *
  * This tool reuses the rembg bundle (background-removal). The 501 gate fires
  * before any settings validation when the bundle is absent. Locally and in CI,
diff --git a/tests/integration/blur-faces.test.ts b/tests/integration/blur-faces.test.ts
index 27334c90..8eb645d0 100644
--- a/tests/integration/blur-faces.test.ts
+++ b/tests/integration/blur-faces.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the blur-faces AI tool (/api/v1/tools/blur-faces).
+ * Integration tests for the blur-faces AI tool (/api/v1/tools/image/blur-faces).
  *
  * The Python sidecar may not be running, so processing tests accept both
  * 200 (sidecar available) and 501 (feature not installed). Validation paths
diff --git a/tests/integration/border.test.ts b/tests/integration/border.test.ts
index 23c32877..9dca6781 100644
--- a/tests/integration/border.test.ts
+++ b/tests/integration/border.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the border tool (/api/v1/tools/border).
+ * Integration tests for the border tool (/api/v1/tools/image/border).
  *
  * Covers solid-color borders, padding, corner radius, shadow, dimension
  * verification, and input validation.
diff --git a/tests/integration/bulk-rename.test.ts b/tests/integration/bulk-rename.test.ts
index 1ab9fd81..bf9de3c1 100644
--- a/tests/integration/bulk-rename.test.ts
+++ b/tests/integration/bulk-rename.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the bulk-rename tool (/api/v1/tools/bulk-rename).
+ * Integration tests for the bulk-rename tool (/api/v1/tools/image/bulk-rename).
  *
  * Covers pattern-based renaming with {{index}}, {{padded}}, {{original}}
  * placeholders, custom start index, ZIP response format, and input validation.
diff --git a/tests/integration/chart-maker.test.ts b/tests/integration/chart-maker.test.ts
index c7a4ae3d..f99a8b25 100644
--- a/tests/integration/chart-maker.test.ts
+++ b/tests/integration/chart-maker.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the chart-maker tool (/api/v1/tools/chart-maker).
+ * Integration tests for the chart-maker tool (/api/v1/tools/files/chart-maker).
  *
  * Factory FILE tool that consumes CSV/JSON and renders hand-rolled SVG
  * rasterized to PNG via sharp. Tests cover bar/line/pie kinds, CSV and JSON
diff --git a/tests/integration/circle-crop.test.ts b/tests/integration/circle-crop.test.ts
index 3ad74624..ff8d54ae 100644
--- a/tests/integration/circle-crop.test.ts
+++ b/tests/integration/circle-crop.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the circle-crop tool (/api/v1/tools/circle-crop).
+ * Integration tests for the circle-crop tool (/api/v1/tools/image/circle-crop).
  *
  * Covers circular masking, PNG output, corner alpha transparency,
  * and center pixel opacity.
diff --git a/tests/integration/collage.test.ts b/tests/integration/collage.test.ts
index 6ba52dab..97ceeb18 100644
--- a/tests/integration/collage.test.ts
+++ b/tests/integration/collage.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the collage tool (/api/v1/tools/collage).
+ * Integration tests for the collage tool (/api/v1/tools/image/collage).
  *
  * Collage accepts multiple images (any field name, type === "file") and
  * arranges them in a template-based grid layout. It uses a custom route
diff --git a/tests/integration/colorize.test.ts b/tests/integration/colorize.test.ts
index f7193d3a..9847bf5e 100644
--- a/tests/integration/colorize.test.ts
+++ b/tests/integration/colorize.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the colorize AI tool (/api/v1/tools/colorize).
+ * Integration tests for the colorize AI tool (/api/v1/tools/image/colorize).
  *
  * The Python sidecar may not be running, so processing tests accept both
  * 200 (sidecar available) and 501 (feature not installed). Validation paths
diff --git a/tests/integration/compare.test.ts b/tests/integration/compare.test.ts
index 2480fe56..b54b27f0 100644
--- a/tests/integration/compare.test.ts
+++ b/tests/integration/compare.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the compare tool (/api/v1/tools/compare).
+ * Integration tests for the compare tool (/api/v1/tools/image/compare).
  *
  * Covers identical-image comparison, different-image comparison,
  * similarity score, diff image generation, and input validation.
diff --git a/tests/integration/compose.test.ts b/tests/integration/compose.test.ts
index 0cb3469b..63b30fff 100644
--- a/tests/integration/compose.test.ts
+++ b/tests/integration/compose.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the compose tool (/api/v1/tools/compose).
+ * Integration tests for the compose tool (/api/v1/tools/image/compose).
  *
  * Compose overlays one image on top of another with position, opacity,
  * and blend mode controls. It uses field names "file" for the base image
diff --git a/tests/integration/crop.test.ts b/tests/integration/crop.test.ts
index 7d34b9d7..53ae0633 100644
--- a/tests/integration/crop.test.ts
+++ b/tests/integration/crop.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the crop tool (/api/v1/tools/crop).
+ * Integration tests for the crop tool (/api/v1/tools/image/crop).
  *
  * This is a Sharp-based tool (no AI sidecar). All processing tests should
  * return 200. Output dimensions are verified by downloading the result and
diff --git a/tests/integration/duotone.test.ts b/tests/integration/duotone.test.ts
index 4efe57a5..4bcf0351 100644
--- a/tests/integration/duotone.test.ts
+++ b/tests/integration/duotone.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the duotone tool (/api/v1/tools/duotone).
+ * Integration tests for the duotone tool (/api/v1/tools/image/duotone).
  *
  * Covers duotone color mapping, black-to-shadow and white-to-highlight
  * pixel assertions with tolerance, intensity blending, and schema validation.
diff --git a/tests/integration/enhance-faces.test.ts b/tests/integration/enhance-faces.test.ts
index 18048623..6ca7369a 100644
--- a/tests/integration/enhance-faces.test.ts
+++ b/tests/integration/enhance-faces.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the enhance-faces AI tool (/api/v1/tools/enhance-faces).
+ * Integration tests for the enhance-faces AI tool (/api/v1/tools/image/enhance-faces).
  *
  * The Python sidecar may not be running, so processing tests accept both
  * 200 (sidecar available) and 501 (feature not installed). Validation paths
diff --git a/tests/integration/erase-object.test.ts b/tests/integration/erase-object.test.ts
index 6f07dba3..1c845061 100644
--- a/tests/integration/erase-object.test.ts
+++ b/tests/integration/erase-object.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the erase-object AI tool (/api/v1/tools/erase-object).
+ * Integration tests for the erase-object AI tool (/api/v1/tools/image/erase-object).
  *
  * This tool requires BOTH an image and a mask file. The Python sidecar may not
  * be running, so processing tests accept both 200 (sidecar available) and
diff --git a/tests/integration/factory-multi-input.test.ts b/tests/integration/factory-multi-input.test.ts
index 24bbea03..f043ca77 100644
--- a/tests/integration/factory-multi-input.test.ts
+++ b/tests/integration/factory-multi-input.test.ts
@@ -7,7 +7,7 @@
  */
 import { readFileSync } from "node:fs";
 import { join } from "node:path";
-import { TOOLS } from "@snapotter/shared";
+import { apiToolPath, TOOLS } from "@snapotter/shared";
 import { eq } from "drizzle-orm";
 import { afterAll, beforeAll, describe, expect, it } from "vitest";
 import { db, schema } from "../../apps/api/src/db/index.js";
@@ -122,7 +122,7 @@ describe("Factory multi-input (maxInputs)", () => {
 
     const res = await testApp.app.inject({
       method: "POST",
-      url: "/api/v1/tools/multi-concat",
+      url: apiToolPath("multi-concat"),
       headers: {
         authorization: `Bearer ${adminToken}`,
         "content-type": contentType,
@@ -187,7 +187,7 @@ describe("Factory multi-input (maxInputs)", () => {
 
     const res = await testApp.app.inject({
       method: "POST",
-      url: "/api/v1/tools/multi-concat",
+      url: apiToolPath("multi-concat"),
       headers: {
         authorization: `Bearer ${adminToken}`,
         "content-type": contentType,
@@ -211,7 +211,7 @@ describe("Factory multi-input (maxInputs)", () => {
 
     const res = await testApp.app.inject({
       method: "POST",
-      url: "/api/v1/tools/multi-validate",
+      url: apiToolPath("multi-validate"),
       headers: {
         authorization: `Bearer ${adminToken}`,
         "content-type": contentType,
diff --git a/tests/integration/find-duplicates.test.ts b/tests/integration/find-duplicates.test.ts
index 1ae6aa6e..b62c4e03 100644
--- a/tests/integration/find-duplicates.test.ts
+++ b/tests/integration/find-duplicates.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the find-duplicates tool (/api/v1/tools/find-duplicates).
+ * Integration tests for the find-duplicates tool (/api/v1/tools/image/find-duplicates).
  *
  * Covers duplicate detection with identical images, detection of unique images,
  * threshold tuning, response structure, and input validation.
diff --git a/tests/integration/gif-webp.test.ts b/tests/integration/gif-webp.test.ts
index 9f5c9f3c..7fa4a01b 100644
--- a/tests/integration/gif-webp.test.ts
+++ b/tests/integration/gif-webp.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the gif-webp tool (/api/v1/tools/gif-webp).
+ * Integration tests for the gif-webp tool (/api/v1/tools/image/gif-webp).
  *
  * Covers GIF-to-WebP, WebP-to-GIF conversions with animation preservation,
  * and extension validation.
diff --git a/tests/integration/histogram.test.ts b/tests/integration/histogram.test.ts
index cd6ef791..4a7add12 100644
--- a/tests/integration/histogram.test.ts
+++ b/tests/integration/histogram.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the histogram tool (/api/v1/tools/histogram).
+ * Integration tests for the histogram tool (/api/v1/tools/image/histogram).
  *
  * Covers PNG output, bins + stats payload, backward-compat mean/max fields,
  * and channel accuracy with a pure-red fixture.
diff --git a/tests/integration/image-pad.test.ts b/tests/integration/image-pad.test.ts
index 92502fb3..5e345c88 100644
--- a/tests/integration/image-pad.test.ts
+++ b/tests/integration/image-pad.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the image-pad tool (/api/v1/tools/image-pad).
+ * Integration tests for the image-pad tool (/api/v1/tools/image/image-pad).
  *
  * Covers aspect-ratio padding, color/transparent/blur backgrounds,
  * custom ratios, dimension math, and schema validation.
diff --git a/tests/integration/info.test.ts b/tests/integration/info.test.ts
index 91fedb6b..725c6574 100644
--- a/tests/integration/info.test.ts
+++ b/tests/integration/info.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the info tool (/api/v1/tools/info).
+ * Integration tests for the info tool (/api/v1/tools/image/info).
  *
  * Covers image metadata extraction: dimensions, format, color space,
  * histogram, EXIF presence, and input validation.
diff --git a/tests/integration/lqip-placeholder.test.ts b/tests/integration/lqip-placeholder.test.ts
index da213e98..95e55928 100644
--- a/tests/integration/lqip-placeholder.test.ts
+++ b/tests/integration/lqip-placeholder.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the lqip-placeholder tool (/api/v1/tools/lqip-placeholder).
+ * Integration tests for the lqip-placeholder tool (/api/v1/tools/image/lqip-placeholder).
  *
  * Covers LQIP generation, data URI prefix, strategy variants, output size, and schema validation.
  */
diff --git a/tests/integration/meme-generator.test.ts b/tests/integration/meme-generator.test.ts
index 6ab4df66..fbe17938 100644
--- a/tests/integration/meme-generator.test.ts
+++ b/tests/integration/meme-generator.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the meme-generator tool (/api/v1/tools/meme-generator).
+ * Integration tests for the meme-generator tool (/api/v1/tools/image/meme-generator).
  *
  * Supports two input modes:
  * 1. Template mode: JSON body with templateId (no file upload)
diff --git a/tests/integration/noise-removal.test.ts b/tests/integration/noise-removal.test.ts
index 1f23c67d..d83ca148 100644
--- a/tests/integration/noise-removal.test.ts
+++ b/tests/integration/noise-removal.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the noise-removal AI tool (/api/v1/tools/noise-removal).
+ * Integration tests for the noise-removal AI tool (/api/v1/tools/image/noise-removal).
  *
  * The Python sidecar may not be running, so processing tests accept both
  * 200 (sidecar available) and 501 (feature not installed). Validation paths
diff --git a/tests/integration/ocr-pdf.test.ts b/tests/integration/ocr-pdf.test.ts
index 2cf1399a..4dd48e96 100644
--- a/tests/integration/ocr-pdf.test.ts
+++ b/tests/integration/ocr-pdf.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the ocr-pdf tool (/api/v1/tools/ocr-pdf).
+ * Integration tests for the ocr-pdf tool (/api/v1/tools/pdf/ocr-pdf).
  *
  * The OCR bundle (PaddleOCR / Tesseract) is 3-4 GB and not installed locally
  * or in any verification environment this wave. The 501 gate is always hit.
diff --git a/tests/integration/ocr.test.ts b/tests/integration/ocr.test.ts
index 688921fc..70b53612 100644
--- a/tests/integration/ocr.test.ts
+++ b/tests/integration/ocr.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the OCR AI tool (/api/v1/tools/ocr).
+ * Integration tests for the OCR AI tool (/api/v1/tools/image/ocr).
  *
  * The Python sidecar may not be running, so processing tests accept both
  * 200 (sidecar available) and 501 (feature not installed). Validation paths
diff --git a/tests/integration/pixelate.test.ts b/tests/integration/pixelate.test.ts
index bc53351d..e491da9f 100644
--- a/tests/integration/pixelate.test.ts
+++ b/tests/integration/pixelate.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the pixelate tool (/api/v1/tools/pixelate).
+ * Integration tests for the pixelate tool (/api/v1/tools/image/pixelate).
  *
  * Covers full-image pixelation, region pixelation, dimension preservation,
  * region bounds validation, region clamping, and schema validation.
diff --git a/tests/integration/qr-generate.test.ts b/tests/integration/qr-generate.test.ts
index 0feb90dd..7a12c237 100644
--- a/tests/integration/qr-generate.test.ts
+++ b/tests/integration/qr-generate.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the qr-generate tool (/api/v1/tools/qr-generate).
+ * Integration tests for the qr-generate tool (/api/v1/tools/image/qr-generate).
  *
  * Covers QR code generation from text/URL input, custom size and colors,
  * error correction levels, download verification, and input validation.
diff --git a/tests/integration/red-eye-removal.test.ts b/tests/integration/red-eye-removal.test.ts
index 67d72e71..c8699471 100644
--- a/tests/integration/red-eye-removal.test.ts
+++ b/tests/integration/red-eye-removal.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the red-eye-removal tool (/api/v1/tools/red-eye-removal).
+ * Integration tests for the red-eye-removal tool (/api/v1/tools/image/red-eye-removal).
  *
  * This tool requires the Python sidecar (MediaPipe face-detection bundle).
  * Tests accept both 200 (sidecar running) and 501 (not installed) for the
diff --git a/tests/integration/remove-background.test.ts b/tests/integration/remove-background.test.ts
index 1452a62b..d0032f8c 100644
--- a/tests/integration/remove-background.test.ts
+++ b/tests/integration/remove-background.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the remove-background tool (/api/v1/tools/remove-background).
+ * Integration tests for the remove-background tool (/api/v1/tools/image/remove-background).
  *
  * This tool requires the Python sidecar (rembg). Tests accept both 200
  * (sidecar running) and 501 (not installed) for the processing path while
diff --git a/tests/integration/resize.test.ts b/tests/integration/resize.test.ts
index e7319e45..1134be43 100644
--- a/tests/integration/resize.test.ts
+++ b/tests/integration/resize.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the resize tool (/api/v1/tools/resize).
+ * Integration tests for the resize tool (/api/v1/tools/image/resize).
  *
  * This is a Sharp-based tool (no AI sidecar). All processing tests should
  * return 200. Output dimensions are verified by downloading the result and
diff --git a/tests/integration/restore-photo.test.ts b/tests/integration/restore-photo.test.ts
index a921b587..5c8d9765 100644
--- a/tests/integration/restore-photo.test.ts
+++ b/tests/integration/restore-photo.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the restore-photo tool (/api/v1/tools/restore-photo).
+ * Integration tests for the restore-photo tool (/api/v1/tools/image/restore-photo).
  *
  * This tool requires the Python sidecar (LaMa / Real-ESRGAN / face enhancement).
  * Tests accept both 200 (sidecar running) and 501 (not installed) for the
diff --git a/tests/integration/rotate.test.ts b/tests/integration/rotate.test.ts
index 0b97d94c..ba993cba 100644
--- a/tests/integration/rotate.test.ts
+++ b/tests/integration/rotate.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the rotate tool (/api/v1/tools/rotate).
+ * Integration tests for the rotate tool (/api/v1/tools/image/rotate).
  *
  * This is a Sharp-based tool (no AI sidecar). All processing tests should
  * return 200. Output dimensions are verified by downloading the result and
diff --git a/tests/integration/smart-crop.test.ts b/tests/integration/smart-crop.test.ts
index e48ef0fd..beba4e8b 100644
--- a/tests/integration/smart-crop.test.ts
+++ b/tests/integration/smart-crop.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the smart-crop tool (/api/v1/tools/smart-crop).
+ * Integration tests for the smart-crop tool (/api/v1/tools/image/smart-crop).
  *
  * Smart crop has three modes:
  *   - subject (Sharp attention/entropy strategy)
diff --git a/tests/integration/split.test.ts b/tests/integration/split.test.ts
index 2f5e32fe..00196494 100644
--- a/tests/integration/split.test.ts
+++ b/tests/integration/split.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the split tool (/api/v1/tools/split).
+ * Integration tests for the split tool (/api/v1/tools/image/split).
  *
  * The split tool divides an image into a grid of tiles and returns a ZIP.
  * It uses reply.hijack() to stream the ZIP directly, so responses are
diff --git a/tests/integration/sprite-sheet.test.ts b/tests/integration/sprite-sheet.test.ts
index 16b2e784..dac7b671 100644
--- a/tests/integration/sprite-sheet.test.ts
+++ b/tests/integration/sprite-sheet.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the sprite-sheet tool (/api/v1/tools/sprite-sheet).
+ * Integration tests for the sprite-sheet tool (/api/v1/tools/image/sprite-sheet).
  *
  * Covers grid layout, dimension math, frames payload, and minimum input guard.
  */
diff --git a/tests/integration/stitch.test.ts b/tests/integration/stitch.test.ts
index 736ce5ea..7ec8dac3 100644
--- a/tests/integration/stitch.test.ts
+++ b/tests/integration/stitch.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the stitch tool (/api/v1/tools/stitch).
+ * Integration tests for the stitch tool (/api/v1/tools/image/stitch).
  *
  * Stitch joins multiple images horizontally, vertically, or in a grid.
  * It requires at least 2 images and accepts them via any file field name
diff --git a/tests/integration/transcribe-audio.test.ts b/tests/integration/transcribe-audio.test.ts
index cc773b9a..89a7b6cd 100644
--- a/tests/integration/transcribe-audio.test.ts
+++ b/tests/integration/transcribe-audio.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the transcribe-audio tool (/api/v1/tools/transcribe-audio).
+ * Integration tests for the transcribe-audio tool (/api/v1/tools/audio/transcribe-audio).
  *
  * The transcription bundle (faster-whisper) is not installed locally, so the
  * 501 gate is always hit. Validation paths (bad settings) are tested after
diff --git a/tests/integration/transparency-fixer.test.ts b/tests/integration/transparency-fixer.test.ts
index 336f6e95..8da2b2c5 100644
--- a/tests/integration/transparency-fixer.test.ts
+++ b/tests/integration/transparency-fixer.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the transparency-fixer tool (/api/v1/tools/transparency-fixer).
+ * Integration tests for the transparency-fixer tool (/api/v1/tools/image/transparency-fixer).
  *
  * This tool requires the Python sidecar (rembg with BiRefNet HR-matting model).
  * Tests accept 200, 202 (sidecar running), and 501 (not installed) for
diff --git a/tests/integration/upscale.test.ts b/tests/integration/upscale.test.ts
index c9964e17..dc3ee392 100644
--- a/tests/integration/upscale.test.ts
+++ b/tests/integration/upscale.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the upscale tool (/api/v1/tools/upscale).
+ * Integration tests for the upscale tool (/api/v1/tools/image/upscale).
  *
  * This tool uses async processing: valid requests return 202 with a jobId,
  * and the result is delivered via SSE. Tests accept both 202 (processing
diff --git a/tests/integration/vignette.test.ts b/tests/integration/vignette.test.ts
index cae1f25b..8baac2f3 100644
--- a/tests/integration/vignette.test.ts
+++ b/tests/integration/vignette.test.ts
@@ -1,5 +1,5 @@
 /**
- * Integration tests for the vignette tool (/api/v1/tools/vignette).
+ * Integration tests for the vignette tool (/api/v1/tools/image/vignette).
  *
  * Covers vignette application, corner-darker-than-source assertion,
  * dimension preservation, and schema validation.
diff --git a/tests/unit/scripts/rewrite-tool-paths.test.ts b/tests/unit/scripts/rewrite-tool-paths.test.ts
index 85fa778d..f0afae89 100644
--- a/tests/unit/scripts/rewrite-tool-paths.test.ts
+++ b/tests/unit/scripts/rewrite-tool-paths.test.ts
@@ -73,6 +73,15 @@ describe("rewriteToolPaths", () => {
     );
   });
 
+  it("treats ) and , as segment boundaries (prose/comments)", () => {
+    expect(rewriteToolPaths("see (/api/v1/tools/crop) for details", MAP)).toBe(
+      "see (/api/v1/tools/image/crop) for details",
+    );
+    expect(rewriteToolPaths("endpoints /api/v1/tools/crop, /api/v1/tools/resize", MAP)).toBe(
+      "endpoints /api/v1/tools/image/crop, /api/v1/tools/image/resize",
+    );
+  });
+
   it("throws if an id is also a section slug (idempotency invariant)", () => {
     expect(() => rewriteToolPaths("x", { image: "image" })).toThrow(/idempotency/);
   });
diff --git a/tests/unit/security-input-validation.test.ts b/tests/unit/security-input-validation.test.ts
index 8079856f..181f0511 100644
--- a/tests/unit/security-input-validation.test.ts
+++ b/tests/unit/security-input-validation.test.ts
@@ -130,7 +130,7 @@ describe("ExifTool security: internal path stripping", () => {
   });
 
   it("does not strip non-sensitive paths", () => {
-    const msg = "Use /api/v1/tools/convert endpoint";
+    const msg = "Use /api/v1/tools/image/convert endpoint";
     expect(stripInternalPaths(msg)).toBe(msg);
   });
 });