{
  "contractVersion": "zplmagic-agent-contract-v1",
  "documentVersion": "zplmagic-agent-document-v1",
  "app": {
    "name": "ZPL Magic",
    "url": "https://zplmagic.com",
    "instructionsUrl": "https://zplmagic.com/agent/instructions.md",
    "contractUrl": "https://zplmagic.com/agent/contract.json",
    "llmsUrl": "https://zplmagic.com/llms.txt"
  },
  "visualGuidance": "Keep a visible browser view, such as Chrome, available whenever practical so the user can see and inspect the rendered label while you work. Internal browser or screenshot tooling may also be used, but do not hide the label's visual state from the user.",
  "readSurface": {
    "openUrl": "https://zplmagic.com/?agent=1",
    "type": "hidden-dom",
    "selectors": {
      "currentDocument": "#zplmagic-agent-current-document",
      "currentZpl": "#zplmagic-agent-current-zpl",
      "currentImportUrl": "#zplmagic-agent-current-import-url",
      "importError": ".agent-import-error"
    },
    "description": "Open the agent URL and read these hidden DOM fields from the page. They are intentionally not visible to the user. Do not execute JavaScript in the page to read state."
  },
  "writeSurface": {
    "type": "url-import",
    "preferredUrl": "https://zplmagic.com/agent/import#agentDoc=<base64url-json-document>",
    "alsoAccepted": [
      "https://zplmagic.com/?agentDoc=<base64url-json-document>",
      "https://zplmagic.com/#agentDoc=<base64url-json-document>"
    ],
    "encoding": "base64url(JSON.stringify(document))",
    "description": "Write by opening a new browser tab to the import URL. The document is normalized and rendered immediately. Clean URLs load the normal hardcoded ZPL Magic example."
  },
  "encodingSnippet": "btoa(unescape(encodeURIComponent(JSON.stringify(document)))).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\")",
  "documentSchema": {
    "type": "object",
    "required": ["label", "elements"],
    "properties": {
      "version": {
        "const": "zplmagic-agent-document-v1"
      },
      "label": {
        "$ref": "#/schemas/labelConfig"
      },
      "elements": {
        "type": "array",
        "items": {
          "$ref": "#/schemas/element"
        }
      }
    }
  },
  "schemas": {
    "labelConfig": {
      "type": "object",
      "properties": {
        "uom": {
          "enum": ["inches", "mm"],
          "default": "inches"
        },
        "printer_width": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 12,
          "default": 4
        },
        "orientation": {
          "enum": ["portrait", "landscape", "portrait-reversed", "landscape-reversed"],
          "default": "portrait"
        },
        "label_width": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 12,
          "default": 4
        },
        "label_height": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 24,
          "default": 6
        },
        "dpi": {
          "enum": [203, 300],
          "default": 203
        }
      }
    },
    "commonElementFields": {
      "properties": {
        "id": {
          "type": ["string", "number"],
          "description": "Stable ID. If omitted, ZPL Magic generates one."
        },
        "zplX": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2000
        },
        "zplY": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2000
        },
        "zIndex": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "element": {
      "oneOf": [
        { "$ref": "#/schemas/textElement" },
        { "$ref": "#/schemas/barcodeElement" },
        { "$ref": "#/schemas/qrcodeElement" },
        { "$ref": "#/schemas/boxElement" },
        { "$ref": "#/schemas/circleElement" },
        { "$ref": "#/schemas/straightLineElement" },
        { "$ref": "#/schemas/gridElement" }
      ]
    },
    "textElement": {
      "type": "object",
      "required": ["type", "zplX", "zplY"],
      "properties": {
        "type": { "const": "text" },
        "data": { "type": "string", "default": "Sample Text" },
        "mergeField": { "type": "string", "default": "" },
        "fontSize": { "type": "integer", "minimum": 10, "maximum": 100, "default": 30 },
        "fontFamily": { "type": "string", "default": "Swiss721BoldCondensed, Arial" },
        "rotation": { "enum": ["N", "R", "I", "B"], "default": "N" },
        "color": { "enum": ["black", "white"], "default": "black" },
        "enableLineWrapping": { "type": "boolean", "default": false },
        "blockWidth": { "type": "integer", "minimum": 50, "maximum": 800, "default": 300 },
        "textJustification": { "enum": ["L", "C", "R"], "default": "L" },
        "maxLines": { "type": "integer", "minimum": 1, "maximum": 20, "default": 3 }
      }
    },
    "barcodeElement": {
      "type": "object",
      "required": ["type", "zplX", "zplY"],
      "properties": {
        "type": { "const": "barcode" },
        "barcodeType": { "enum": ["Code128", "BC"], "default": "Code128" },
        "data": { "type": "string", "default": "12345678" },
        "mergeField": { "type": "string", "default": "" },
        "moduleWidth": { "type": "integer", "minimum": 1, "maximum": 10, "default": 2 },
        "height": { "type": "integer", "minimum": 10, "maximum": 200, "default": 50 },
        "ratio": { "type": "integer", "minimum": 2, "maximum": 3, "default": 3 },
        "rotation": { "enum": ["N", "R", "I", "B"], "default": "N" }
      }
    },
    "qrcodeElement": {
      "type": "object",
      "required": ["type", "zplX", "zplY"],
      "properties": {
        "type": { "const": "qrcode" },
        "data": { "type": "string", "default": "1234567890" },
        "mergeField": { "type": "string", "default": "" }
      },
      "computedReadOnly": {
        "magnification": "ZPL Magic computes this from mergeField when present, otherwise data. Agents must not set it."
      }
    },
    "boxElement": {
      "type": "object",
      "required": ["type", "zplX", "zplY"],
      "properties": {
        "type": { "const": "box" },
        "width": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 240 },
        "height": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 240 },
        "thickness": { "type": "integer", "minimum": 1, "maximum": 100, "default": 6 },
        "color": { "enum": ["B", "W"], "default": "B" },
        "rounding": { "type": "integer", "minimum": 0, "maximum": 8, "default": 0 }
      }
    },
    "circleElement": {
      "type": "object",
      "required": ["type", "zplX", "zplY"],
      "properties": {
        "type": { "const": "circle" },
        "size": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 200 },
        "thickness": { "type": "integer", "minimum": 1, "maximum": 100, "default": 8 },
        "color": { "enum": ["B", "W"], "default": "B" }
      }
    },
    "straightLineElement": {
      "type": "object",
      "required": ["type", "zplX", "zplY"],
      "properties": {
        "type": { "const": "straightLine" },
        "orientation": { "enum": ["horizontal", "vertical"], "default": "horizontal" },
        "length": { "type": "integer", "minimum": 17, "maximum": 2000, "default": 240 },
        "thickness": { "type": "integer", "minimum": 2, "maximum": 100, "default": 8 },
        "color": { "enum": ["B", "W"], "default": "B" }
      }
    },
    "gridElement": {
      "type": "object",
      "required": ["type", "zplX", "zplY"],
      "properties": {
        "type": { "const": "grid" },
        "rows": { "type": "integer", "minimum": 1, "maximum": 50, "default": 3 },
        "columns": { "type": "integer", "minimum": 1, "maximum": 50, "default": 3 },
        "width": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 300 },
        "height": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 180 },
        "thickness": { "type": "integer", "minimum": 1, "maximum": 100, "default": 4 },
        "color": { "enum": ["B", "W"], "default": "B" }
      }
    }
  },
  "constraints": {
    "unsupportedElementTypes": {
      "image": "Images must be added, cropped, and edited by the user through the ZPL Magic UI."
    },
    "writeModel": "Always write a complete document. To make an edit, read the current document, modify it, encode the whole document, and open a new import URL.",
    "invalidImportBehavior": "Invalid URL imports show a non-blocking error banner and leave the current label unchanged."
  },
  "examples": {
    "document": {
      "version": "zplmagic-agent-document-v1",
      "label": {
        "uom": "inches",
        "printer_width": 4,
        "orientation": "portrait",
        "label_width": 4,
        "label_height": 6,
        "dpi": 203
      },
      "elements": [
        {
          "id": "title",
          "type": "text",
          "zplX": 80,
          "zplY": 80,
          "data": "ACME PARTS",
          "fontSize": 48
        },
        {
          "id": "sku-barcode",
          "type": "barcode",
          "zplX": 80,
          "zplY": 420,
          "data": "SKU-12345",
          "moduleWidth": 3,
          "height": 120
        },
        {
          "id": "contact-qr",
          "type": "qrcode",
          "zplX": 520,
          "zplY": 80,
          "data": "https://zplmagic.com"
        }
      ]
    },
    "importUrl": "https://zplmagic.com/agent/import#agentDoc=<base64url-json-document>"
  }
}
