{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://makerfern.com/tools.schema.json",
  "title": "Makerfern tool catalogue",
  "description": "The shape of /tools.json, schema version 1. Written by the site build from the same lists as the Tools menu and /for-assistants. A field is only ever added in a new schemaVersion.",
  "type": "object",
  "additionalProperties": false,
  "required": ["$schema", "schemaVersion", "name", "url", "description", "updated", "humanPage", "llmsTxt", "guidance", "privacy", "proPlan", "groups", "tools"],
  "properties": {
    "$schema": { "type": "string", "pattern": "^https://" },
    "schemaVersion": { "type": "integer", "enum": [1] },
    "name": { "type": "string", "minLength": 1 },
    "url": { "type": "string", "pattern": "^https://" },
    "description": { "type": "string", "minLength": 1 },
    "updated": { "type": ["string", "null"], "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Date of the newest live entry in What's new." },
    "humanPage": { "type": "string", "pattern": "^https://" },
    "llmsTxt": { "type": "string", "pattern": "^https://" },
    "guidance": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
    "privacy": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
    "proPlan": {
      "type": "object",
      "additionalProperties": false,
      "required": ["optional", "url", "monthlyUsd", "yearlyUsd", "lifetimeUsd", "summary"],
      "properties": {
        "optional": { "type": "boolean" },
        "url": { "type": "string", "pattern": "^https://" },
        "monthlyUsd": { "type": "number" },
        "yearlyUsd": { "type": "number" },
        "lifetimeUsd": { "type": "number" },
        "summary": { "type": "string", "minLength": 1 }
      }
    },
    "groups": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["title", "tools"],
        "properties": {
          "title": { "type": "string", "minLength": 1 },
          "tools": { "type": "array", "minItems": 1, "items": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" } }
        }
      }
    },
    "tools": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/tool" } }
  },
  "$defs": {
    "tool": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "name", "url", "group", "family", "summary", "tasks", "inputs", "outputs", "pro", "onDevice", "serverNote", "model", "parameters", "updated"],
      "properties": {
        "id": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$", "description": "Stable: the last part of the tool's address." },
        "name": { "type": "string", "minLength": 1 },
        "url": { "type": "string", "pattern": "^https://[^ ]+$", "description": "The tool's own page: the link to give." },
        "group": { "type": "string", "minLength": 1, "description": "The group in the Tools menu." },
        "family": { "type": ["string", "null"], "enum": ["image-converter", null], "description": "image-converter on the eight converter pages, which are one tool opened on different starting settings." },
        "summary": { "type": "string", "minLength": 1, "description": "One plain sentence." },
        "tasks": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
        "inputs": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/input" } },
        "outputs": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/output" } },
        "pro": {
          "type": "object",
          "additionalProperties": false,
          "required": ["available", "features"],
          "properties": {
            "available": { "type": "boolean", "description": "True when at least one output is Pro." },
            "features": { "type": "array", "items": { "type": "string", "minLength": 1 } }
          }
        },
        "onDevice": { "type": "boolean", "description": "True when the work happens in the browser and nothing is uploaded." },
        "serverNote": { "type": ["string", "null"], "description": "When onDevice is false: what is sent to the server." },
        "model": {
          "oneOf": [
            { "type": "null" },
            {
              "type": "object",
              "additionalProperties": false,
              "required": ["name", "downloadMb", "optional", "when"],
              "properties": {
                "name": { "type": "string", "minLength": 1 },
                "downloadMb": { "type": "array", "minItems": 2, "maxItems": 2, "items": { "type": "integer" }, "description": "Download size in MB: WebAssembly, then WebGPU." },
                "optional": { "type": "boolean", "description": "True when the model is used only for an option of the tool." },
                "when": { "type": "string", "minLength": 1 }
              }
            }
          ]
        },
        "parameters": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["name", "example", "description"],
            "properties": {
              "name": { "type": "string", "pattern": "^[a-z]+$" },
              "example": { "type": "string", "pattern": "^https://" },
              "description": { "type": "string", "minLength": 1 }
            }
          }
        },
        "updated": { "type": ["string", "null"], "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Date of the tool's latest live entry in What's new." }
      }
    },
    "input": {
      "type": "object",
      "additionalProperties": false,
      "required": ["kind", "formats", "description"],
      "properties": {
        "kind": { "type": "string", "enum": ["image", "audio", "svg", "text", "numbers", "url"] },
        "formats": { "type": "array", "items": { "type": "string", "pattern": "^[A-Z0-9]{2,5}$" }, "description": "File formats the picker accepts. Empty for typed input." },
        "description": { "type": "string", "minLength": 1 }
      }
    },
    "output": {
      "type": "object",
      "additionalProperties": false,
      "required": ["format", "pro", "description"],
      "properties": {
        "format": { "type": "string", "pattern": "^[A-Z0-9]{2,6}$", "description": "A file format, or REPORT / RESULT when the answer is shown on the page and nothing is downloaded." },
        "pro": { "type": "boolean" },
        "description": { "type": "string", "minLength": 1 }
      }
    }
  }
}
