{
  "schemaVersion": "huejoy/agent-interface/3",
  "name": "Huejoy agent interface",
  "description": "Browser-agent discovery and operations for Huejoy. This is a custom DOM/WebMCP contract, not an A2A agent card or HTTP execution endpoint.",
  "documents": {
    "legacy": "/agent.json",
    "current": "/agent-v3.json"
  },
  "channelDefinitions": {
    "dom": {
      "description": "Visible page controls declared by each operation's DOM bindings.",
      "targeting": "A selector may match hidden desktop/mobile duplicates or many roles/cards. Select exactly one visible, enabled control. Match role with data-agent-role and index with data-agent-index; never click every match. Role IDs must occur in the current handoff palette. Collection indices are zero-based DOM attributes, not DOM positions; re-read after any collection change.",
      "concurrency": "DOM actions do not accept expectedRevision or provide atomic compare-and-set. Serialize interactions, read the current revision before acting, then verify the resulting state. Use WebMCP expectedRevision for guarded mutations when available.",
      "results": "Read the latest #huejoy-agent-handoff and #huejoy-agent-config after a mutation. huejoy:agent-state is a carrier invalidation signal, not an action receipt. Side effects and idempotent no-ops may leave revision unchanged. Use each operation completion rule.",
      "errors": "While ready remains true, root error-code/error-message report rejected color or seed drafts (INVALID_COLOR/INVALID_SEED); canonical state remains valid. The corresponding field sets aria-invalid. Editing the rejected field, valid submission (including a no-op), or replacing palette colors clears its error. Load errors take precedence, set ready=false, and require start-fresh. Re-read root attributes after form commits; draft rejection does not advance the handoff revision or emit a state event.",
      "inputErrors": [
        {
          "code": "INVALID_COLOR",
          "description": "A color draft failed six-digit hex validation; canonical palette remains ready.",
          "recoverable": true,
          "recoveryOperations": [
            "set-role-color"
          ]
        },
        {
          "code": "INVALID_SEED",
          "description": "A seed draft failed the exact-state seed boundary; canonical palette remains ready.",
          "recoverable": true,
          "recoveryOperations": [
            "apply-seed"
          ]
        }
      ],
      "history": "Manual hex/picker changes update the live palette immediately. They create one History entry after 20000 ms without further color edits; a new edit restarts the timer. While data-huejoy-history-pending=true, handoff selection identifies the source History/Saved entry, not a snapshot of the current edited colors. Save, share, export and WebMCP read the live edited palette. Undo/Escape or palette navigation cancels the pending edit and timer. Discrete generation/agent mutations commit their own result and cancel the timer. Lock/order/presentation changes during a manual edit join its pending entry. Check historyPending directly; a History-only commit need not advance the handoff revision."
    },
    "webmcp": {
      "description": "Progressive same-document tools registered only when the browser exposes document.modelContext.registerTool.",
      "api": "document.modelContext.registerTool",
      "reviewedOn": "2026-09-19",
      "sameDocumentOnly": true,
      "remoteEndpoint": false
    }
  },
  "legacyInterface": {
    "schemaVersion": "huejoy/agent-interface/1",
    "rootSelector": "#app[data-huejoy-agent-contract='huejoy/agent/1']",
    "configSelector": "#huejoy-agent-config",
    "updateEvent": "huejoy:agent-state",
    "activeRoleAttribute": "data-huejoy-active-role",
    "actions": [
      {
        "id": "reroll",
        "selector": "[data-agent-action='reroll']"
      },
      {
        "id": "cycle-gradient-order",
        "selector": "[data-agent-action='cycle-gradient-order']"
      },
      {
        "id": "cycle-pattern",
        "selector": "[data-agent-action='cycle-pattern']"
      },
      {
        "id": "set-pattern",
        "selector": "[data-agent-action='set-pattern']"
      },
      {
        "id": "set-rotation",
        "selector": "[data-agent-action='set-rotation']"
      },
      {
        "id": "select-primary",
        "selector": "[data-agent-action='select-primary'][data-agent-role]"
      },
      {
        "id": "invert-color-chain",
        "selector": "[data-agent-action='invert-color-chain']"
      },
      {
        "id": "toggle-lock",
        "selector": "[data-agent-action='toggle-lock'][data-agent-role]"
      },
      {
        "id": "save",
        "selector": "[data-agent-action='save']"
      },
      {
        "id": "remove-saved",
        "selector": "[data-agent-action='remove-saved'][data-agent-index]"
      },
      {
        "id": "open-export",
        "selector": "[data-agent-action='open-export']"
      },
      {
        "id": "export-format",
        "selector": "[data-agent-action='export-format'][data-agent-format]"
      },
      {
        "id": "select-saved",
        "selector": "[data-agent-action='select-saved'][data-agent-index]"
      },
      {
        "id": "select-history",
        "selector": "[data-agent-action='select-history'][data-agent-index]"
      }
    ]
  },
  "stateCarriers": [
    {
      "id": "compatibility-export",
      "selector": "#huejoy-agent-config",
      "windowGlobal": "__HUEJOY_AGENT_CONFIG__",
      "schemaVersion": "huejoy/agent-export/2"
    },
    {
      "id": "portable-handoff",
      "selector": "#huejoy-agent-handoff",
      "windowGlobal": "__HUEJOY_AGENT_HANDOFF__",
      "schemaVersion": "huejoy/agent-handoff/1"
    }
  ],
  "rootState": {
    "selector": "#app[data-huejoy-agent-contract='huejoy/agent/1']",
    "attributes": {
      "ready": "data-huejoy-agent-ready",
      "errorCode": "data-huejoy-agent-error-code",
      "errorMessage": "data-huejoy-agent-error-message",
      "revision": "data-huejoy-agent-revision",
      "status": "data-huejoy-agent-status",
      "selection": "data-huejoy-agent-selection",
      "activeRole": "data-huejoy-active-role",
      "historyPending": "data-huejoy-history-pending"
    }
  },
  "stateEvent": {
    "name": "huejoy:agent-state",
    "schemaVersion": "huejoy/agent-state-event/1",
    "detailSchema": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "schemaVersion",
        "revision",
        "status"
      ],
      "properties": {
        "schemaVersion": {
          "const": "huejoy/agent-state-event/1"
        },
        "revision": {
          "type": "integer",
          "minimum": 1
        },
        "status": {
          "enum": [
            "ready",
            "error"
          ]
        }
      }
    },
    "semantics": "Emitted only when the handoff changes, after both JSON carriers and root attributes are current. Detail identifies revision and status; re-read the handoff. One interaction may trigger multiple distinct revisions (for example URL synchronization). No action ID or one-event-per-action guarantee. No-op or side-effect-only actions need not emit."
  },
  "effectDefinitions": [
    {
      "id": "read-state",
      "description": "Reads current browser state without changing it."
    },
    {
      "id": "mutate-palette",
      "description": "Changes portable palette state."
    },
    {
      "id": "mutate-presentation",
      "description": "Changes the portable gradient presentation."
    },
    {
      "id": "mutate-session-context",
      "description": "Changes browser-local selection or view state."
    },
    {
      "id": "persist-local",
      "description": "Writes to browser-local storage."
    },
    {
      "id": "delete-local",
      "description": "Deletes browser-local saved state."
    },
    {
      "id": "write-clipboard",
      "description": "Writes a value to the system clipboard."
    },
    {
      "id": "open-dialog",
      "description": "Opens an in-page dialog."
    },
    {
      "id": "open-native-share",
      "description": "Opens the browser or operating system share surface."
    },
    {
      "id": "start-download",
      "description": "Starts a client-side file download."
    }
  ],
  "errorCodes": [
    {
      "code": "AMBIGUOUS_SHARE_TOKEN",
      "description": "The URL contains more than one compact palette token.",
      "recoverable": true,
      "recoveryOperations": [
        "start-fresh"
      ]
    },
    {
      "code": "MALFORMED_SHARE_TOKEN",
      "description": "The compact palette token is malformed or fails validation.",
      "recoverable": true,
      "recoveryOperations": [
        "start-fresh"
      ]
    },
    {
      "code": "UNSUPPORTED_SHARE_VERSION",
      "description": "The URL uses a compact palette token version this client does not support.",
      "recoverable": true,
      "recoveryOperations": [
        "start-fresh"
      ]
    },
    {
      "code": "INVALID_LEGACY_STATE",
      "description": "The legacy palette state query is invalid.",
      "recoverable": true,
      "recoveryOperations": [
        "start-fresh"
      ]
    },
    {
      "code": "INVALID_STATE",
      "description": "The requested palette state does not satisfy the Huejoy state contract.",
      "recoverable": true,
      "recoveryOperations": [
        "retry",
        "start-fresh"
      ]
    },
    {
      "code": "NOT_READY",
      "description": "The page is not ready to perform the requested operation.",
      "recoverable": true,
      "recoveryOperations": [
        "retry"
      ]
    },
    {
      "code": "INVALID_INPUT",
      "description": "The operation input does not satisfy its declared schema.",
      "recoverable": true,
      "recoveryOperations": [
        "retry"
      ]
    },
    {
      "code": "STALE_REVISION",
      "description": "The supplied expected revision no longer matches current state.",
      "recoverable": true,
      "recoveryOperations": [
        "retry"
      ]
    },
    {
      "code": "INDEX_OUT_OF_RANGE",
      "description": "The requested saved or history index does not exist.",
      "recoverable": true,
      "recoveryOperations": [
        "retry"
      ]
    },
    {
      "code": "STORAGE_UNAVAILABLE",
      "description": "Browser-local storage is unavailable for the requested operation.",
      "recoverable": true,
      "recoveryOperations": [
        "retry"
      ]
    },
    {
      "code": "EXPORT_UNAVAILABLE",
      "description": "The requested export could not be produced.",
      "recoverable": true,
      "recoveryOperations": [
        "retry"
      ]
    },
    {
      "code": "ABORTED",
      "description": "The operation was cancelled before completion.",
      "recoverable": true,
      "recoveryOperations": [
        "retry"
      ]
    },
    {
      "code": "CORRUPT_SHARE_TOKEN",
      "description": "Share token checksum failed.",
      "recoverable": true,
      "recoveryOperations": [
        "start-fresh"
      ]
    }
  ],
  "operations": [
    {
      "id": "get-current-palette",
      "title": "Get current palette",
      "description": "Read the current Huejoy handoff, including typed load errors, without changing page state.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "outputSchema": {
        "$ref": "#/schemas/operationResult"
      },
      "effects": [
        "read-state"
      ],
      "readOnly": true,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready",
        "error"
      ],
      "channels": [
        "webmcp"
      ],
      "webMcpBinding": {
        "toolName": "get_current_palette",
        "description": "Read the current Huejoy palette handoff, revision, selected collection item, and typed load error without changing page state.",
        "annotations": {
          "readOnlyHint": true,
          "consequentialHint": false,
          "untrustedContentHint": false
        },
        "resultValueSchema": {
          "$ref": "#/schemas/agentHandoff"
        }
      },
      "domBindings": []
    },
    {
      "id": "apply-palette-state",
      "title": "Apply palette state",
      "description": "Validate one compact state token or Huejoy share URL, then replace the active palette and record it in history.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "stateToken": {
            "type": "string",
            "minLength": 1,
            "maxLength": 360,
            "description": "Exact hj1, hj2 or hj3 state token."
          },
          "shareUrl": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8192,
            "description": "Huejoy URL containing one exact palette token."
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 1,
            "description": "Current handoff revision. A stale value is rejected."
          }
        },
        "oneOf": [
          {
            "required": [
              "stateToken"
            ],
            "not": {
              "required": [
                "shareUrl"
              ]
            }
          },
          {
            "required": [
              "shareUrl"
            ],
            "not": {
              "required": [
                "stateToken"
              ]
            }
          }
        ]
      },
      "outputSchema": {
        "$ref": "#/schemas/operationResult"
      },
      "effects": [
        "mutate-palette",
        "mutate-presentation",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "channels": [
        "webmcp"
      ],
      "webMcpBinding": {
        "toolName": "apply_palette_state",
        "description": "Apply one exact Huejoy palette from a compact state token or share URL, then return the updated handoff.",
        "annotations": {
          "readOnlyHint": false,
          "consequentialHint": false,
          "untrustedContentHint": false
        },
        "resultValueSchema": {
          "$ref": "#/schemas/agentHandoff"
        }
      },
      "domBindings": []
    },
    {
      "id": "generate-palette",
      "title": "Generate palette",
      "description": "Generate a palette from an optional bounded seed while preserving currently locked role colors.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "seed": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "Optional deterministic palette seed."
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 1,
            "description": "Current handoff revision. A stale value is rejected."
          },
          "colorCount": {
            "type": "integer",
            "minimum": 2,
            "maximum": 8
          },
          "harmony": {
            "enum": [
              "auto",
              "monochromatic",
              "analogous",
              "accented-analogous",
              "complementary",
              "split-complementary",
              "double-split-complementary",
              "triadic",
              "tetradic",
              "square",
              "compound",
              "neutral-accent"
            ]
          }
        }
      },
      "outputSchema": {
        "$ref": "#/schemas/operationResult"
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "channels": [
        "webmcp"
      ],
      "webMcpBinding": {
        "toolName": "generate_palette",
        "description": "Generate a Huejoy palette while preserving locked role colors. Supply a seed for deterministic generation.",
        "annotations": {
          "readOnlyHint": false,
          "consequentialHint": false,
          "untrustedContentHint": false
        },
        "resultValueSchema": {
          "$ref": "#/schemas/agentHandoff"
        }
      },
      "domBindings": []
    },
    {
      "id": "transform-palette",
      "title": "Transform palette",
      "description": "Invert the color chain around a role or cycle the three role positions. Inversion defaults to the active role when role is omitted.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "operation"
        ],
        "properties": {
          "operation": {
            "enum": [
              "invert-color-chain",
              "cycle-color-positions"
            ],
            "description": "Palette transform to apply."
          },
          "role": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ],
            "description": "Role to invert; omitted inversion uses the active role."
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 1,
            "description": "Current handoff revision. A stale value is rejected."
          }
        }
      },
      "outputSchema": {
        "$ref": "#/schemas/operationResult"
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "channels": [
        "webmcp"
      ],
      "webMcpBinding": {
        "toolName": "transform_palette",
        "description": "Invert a role's linked color chain or cycle the three color positions, then return the updated handoff.",
        "annotations": {
          "readOnlyHint": false,
          "consequentialHint": false,
          "untrustedContentHint": false
        },
        "resultValueSchema": {
          "$ref": "#/schemas/agentHandoff"
        }
      },
      "domBindings": []
    },
    {
      "id": "configure-presentation",
      "title": "Configure presentation",
      "description": "Set the gradient pattern, direction, or both without generating new role colors.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "pattern": {
            "enum": [
              "radial",
              "conic",
              "double-radial",
              "wide-radial"
            ],
            "description": "Gradient pattern to display."
          },
          "direction": {
            "enum": [
              "down",
              "diagonal",
              "across",
              "up"
            ],
            "description": "Gradient flow direction to display."
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 1,
            "description": "Current handoff revision. A stale value is rejected."
          },
          "rotation": {
            "type": "integer",
            "minimum": 0,
            "maximum": 359
          }
        },
        "anyOf": [
          {
            "required": [
              "pattern"
            ]
          },
          {
            "required": [
              "direction"
            ]
          },
          {
            "required": [
              "rotation"
            ]
          }
        ]
      },
      "outputSchema": {
        "$ref": "#/schemas/operationResult"
      },
      "effects": [
        "mutate-presentation",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "channels": [
        "webmcp"
      ],
      "webMcpBinding": {
        "toolName": "configure_presentation",
        "description": "Set gradient pattern, direction, or rotation without regenerating palette colors.",
        "annotations": {
          "readOnlyHint": false,
          "consequentialHint": false,
          "untrustedContentHint": false
        },
        "resultValueSchema": {
          "$ref": "#/schemas/agentHandoff"
        }
      },
      "domBindings": []
    },
    {
      "id": "reroll",
      "title": "Reroll palette",
      "description": "Generate a palette with a new random seed while preserving locked colors.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-action='reroll']",
          "legacyActionId": "reroll"
        }
      ],
      "domInstructions": "Click the visible bound button once. It generates a new random seed; use apply-seed for an explicit seed.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "apply-seed",
      "title": "Apply seed",
      "description": "Generate the deterministic palette for an explicit seed.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "seed"
        ],
        "properties": {
          "seed": {
            "type": "string",
            "minLength": 0,
            "maxLength": 128
          }
        }
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-operation='apply-seed']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='apply-seed']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Fill #seed-input with seed, then click the bound Apply button or press Enter in the input. Blank or whitespace uses the default seed; surrounding whitespace is trimmed.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "After commit, read the field aria-invalid and root error attributes. On success, verify the seed or role hex in the handoff. Rejection or an unchanged value does not advance revision."
    },
    {
      "id": "cycle-color-positions",
      "title": "Cycle color positions",
      "description": "Rotate Glow, Anchor, and Bridge through the gradient positions.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-action='cycle-gradient-order']",
          "legacyActionId": "cycle-gradient-order"
        }
      ],
      "domInstructions": "Click once to cycle gradient order without replacing role colors.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "cycle-pattern",
      "title": "Cycle gradient pattern",
      "description": "Advance to the next supported gradient pattern.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-presentation"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-action='cycle-pattern']",
          "legacyActionId": "cycle-pattern"
        }
      ],
      "domInstructions": "Click once to choose the next supported pattern.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "set-gradient-pattern",
      "title": "Set gradient pattern",
      "description": "Set one supported gradient pattern without changing colors.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "pattern"
        ],
        "properties": {
          "pattern": {
            "enum": [
              "radial",
              "conic",
              "double-radial",
              "wide-radial"
            ]
          }
        }
      },
      "effects": [
        "mutate-presentation"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='set-pattern']",
          "legacyActionId": "set-pattern"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='set-pattern']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Select input.pattern on the bound select and dispatch its normal change event.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "set-gradient-rotation",
      "title": "Set gradient rotation",
      "description": "Rotate the gradient without changing colors.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "rotation"
        ],
        "properties": {
          "rotation": {
            "type": "integer",
            "minimum": 0,
            "maximum": 359
          }
        }
      },
      "effects": [
        "mutate-presentation"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='set-rotation']",
          "legacyActionId": "set-rotation"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='set-rotation']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Focus the bound slider. Home sets 0; ArrowRight/ArrowUp add 1, ArrowLeft/ArrowDown subtract 1, PageUp/PageDown change 15, End sets 359. Values wrap; read aria-valuenow. Use Home then rotation ArrowRight presses for an exact value.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "select-primary",
      "title": "Select primary role",
      "description": "Select the palette role used by role-sensitive controls.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ]
          }
        }
      },
      "effects": [
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-action='select-primary'][data-agent-role]",
          "legacyActionId": "select-primary"
        }
      ],
      "domInstructions": "Match data-agent-role to role and click the visible radio or mobile role button.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "copy-hex",
      "title": "Copy role hex",
      "description": "Copy the current six-digit hex value for one palette role.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ]
          }
        }
      },
      "effects": [
        "write-clipboard"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "client-sensitive",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-operation='copy-hex'][data-agent-role]"
        }
      ],
      "domInstructions": "Match data-agent-role to role and click once.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Read the live announcement/Copied feedback. Clipboard writes do not advance the palette revision; the clipboard can fail or be permission-gated."
    },
    {
      "id": "invert-color-chain",
      "title": "Invert color chain",
      "description": "Invert the generated color relationship around a selected role.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "role": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ]
          }
        }
      },
      "effects": [
        "mutate-palette"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-action='invert-color-chain']",
          "legacyActionId": "invert-color-chain"
        }
      ],
      "domInstructions": "If role is supplied, first use select-primary for that role. Then click the inversion button once. Omitted role uses the active role.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "toggle-role-lock",
      "title": "Toggle role lock",
      "description": "Toggle whether a palette role remains fixed during generation.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ]
          }
        }
      },
      "effects": [
        "mutate-palette"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-action='toggle-lock'][data-agent-role]",
          "legacyActionId": "toggle-lock"
        }
      ],
      "domInstructions": "Match data-agent-role to role and click once; read colors[].locked afterward.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "set-role-lock",
      "title": "Set role lock",
      "description": "Set one role's lock to an explicit value without relying on the non-idempotent DOM toggle.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "role",
          "locked"
        ],
        "properties": {
          "role": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ],
            "description": "Palette role whose lock state will be set."
          },
          "locked": {
            "type": "boolean",
            "description": "True to preserve the role color during generation."
          },
          "expectedRevision": {
            "type": "integer",
            "minimum": 1,
            "description": "Current handoff revision. A stale value is rejected."
          }
        }
      },
      "outputSchema": {
        "$ref": "#/schemas/operationResult"
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "channels": [
        "webmcp"
      ],
      "webMcpBinding": {
        "toolName": "set_role_lock",
        "description": "Set one Huejoy color role to an explicit locked or unlocked state, idempotently.",
        "annotations": {
          "readOnlyHint": false,
          "consequentialHint": false,
          "untrustedContentHint": false
        },
        "resultValueSchema": {
          "$ref": "#/schemas/agentHandoff"
        }
      },
      "domBindings": []
    },
    {
      "id": "restore-history",
      "title": "Restore history entry",
      "description": "Restore one browser-session history entry by index.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "index"
        ],
        "properties": {
          "index": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "effects": [
        "mutate-palette",
        "mutate-presentation",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='select-history'][data-agent-index]",
          "legacyActionId": "select-history"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='select-history'][data-agent-index]",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Match data-agent-index to index and click once. If currently previewing Saved, the first click exits that preview; re-read and click the desired History entry again if needed.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "The requested zero-based data-agent-index exists; re-read indices immediately before acting."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "select-saved",
      "title": "Select saved palette",
      "description": "Restore one browser-local saved palette by index.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "index"
        ],
        "properties": {
          "index": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "effects": [
        "mutate-palette",
        "mutate-presentation",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='select-saved'][data-agent-index]",
          "legacyActionId": "select-saved"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='select-saved'][data-agent-index]",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Match data-agent-index to index and click once.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "The requested zero-based data-agent-index exists; re-read indices immediately before acting."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "save",
      "title": "Toggle saved palette",
      "description": "Toggle the exact current configuration in browser-local Saved. Saving at capacity evicts the oldest entry.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "persist-local",
        "delete-local",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "client-sensitive",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-action='save']",
          "legacyActionId": "save"
        }
      ],
      "domInstructions": "Click one visible Save button once. It adds the exact current configuration, or removes it if already saved. The browser-local collection keeps at most five entries.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Verify the Saved card list and Save/Saved button state; indices may shift. The handoff revision can remain unchanged. Read the live announcement for local-storage failure; an announcement alone does not prove persistence."
    },
    {
      "id": "remove-saved",
      "title": "Remove saved palette",
      "description": "Delete one browser-local saved palette by index.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "index"
        ],
        "properties": {
          "index": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "effects": [
        "delete-local"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "client-sensitive",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='remove-saved'][data-agent-index]",
          "legacyActionId": "remove-saved"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='remove-saved'][data-agent-index]",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Match data-agent-index to index and click once, or focus the removal button and press Enter/Space. No hover prerequisite.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "The requested zero-based data-agent-index exists; re-read indices immediately before acting."
      ],
      "completion": "Verify the Saved card list and Save/Saved button state; indices may shift. The handoff revision can remain unchanged. Read the live announcement for local-storage failure; an announcement alone does not prove persistence."
    },
    {
      "id": "open-tools",
      "title": "Open tools",
      "description": "Open the mobile tools drawer, optionally on its history section.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "section": {
            "enum": [
              "history"
            ]
          }
        }
      },
      "effects": [
        "mutate-session-context",
        "open-dialog"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='open-tools']"
        }
      ],
      "domInstructions": "Click the mobile button. For section=history choose data-agent-section=history; otherwise use the Open palette tools button. Already-open tools need no further action.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Verify the named drawer/dialog is visible and focus has entered it. No palette revision is required."
    },
    {
      "id": "open-native-share",
      "title": "Open native share",
      "description": "Open the browser or operating-system share surface for the exact palette link, with clipboard fallback.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "open-native-share",
        "write-clipboard"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "client-sensitive",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='open-native-share']"
        }
      ],
      "domInstructions": "Click once to open native sharing when supported, with clipboard fallback.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding."
      ],
      "completion": "Inspect the native share surface or clipboard fallback and live feedback; cancellation is possible. No palette revision is required."
    },
    {
      "id": "open-export",
      "title": "Open export",
      "description": "Open the in-page export dialog.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-session-context",
        "open-dialog"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='open-export']",
          "legacyActionId": "open-export"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='open-export']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once to open the in-page export dialog.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "Verify the named drawer/dialog is visible and focus has entered it. No palette revision is required."
    },
    {
      "id": "export-format",
      "title": "Export format",
      "description": "Download the current palette in one supported format.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "format"
        ],
        "properties": {
          "format": {
            "enum": [
              "css",
              "json",
              "svg",
              "png"
            ]
          }
        }
      },
      "effects": [
        "start-download"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "client-sensitive",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='export-format'][data-agent-format]",
          "legacyActionId": "export-format"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='export-format'][data-agent-format]",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Use open-export first, then match data-agent-format to format and click the dialog button once.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "The export dialog is open; use open-export first."
      ],
      "completion": "Observe the browser download and inspect its bytes. The live download-started message is not proof of completed file delivery. No palette revision is required."
    },
    {
      "id": "export-palette",
      "title": "Export palette",
      "description": "Return the requested palette representation as data without writing the clipboard or starting a download.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "format"
        ],
        "properties": {
          "format": {
            "enum": [
              "handoff",
              "agent-export-v2",
              "json",
              "css"
            ],
            "description": "Palette representation to return."
          }
        }
      },
      "outputSchema": {
        "$ref": "#/schemas/operationResult"
      },
      "effects": [
        "read-state"
      ],
      "readOnly": true,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "channels": [
        "webmcp"
      ],
      "webMcpBinding": {
        "toolName": "export_palette",
        "description": "Return an explicit palette representation as structured text without opening a dialog, copying, or downloading.",
        "annotations": {
          "readOnlyHint": true,
          "consequentialHint": false,
          "untrustedContentHint": false
        },
        "resultValueSchema": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "format",
            "mediaType",
            "content"
          ],
          "properties": {
            "format": {
              "enum": [
                "handoff",
                "agent-export-v2",
                "json",
                "css"
              ]
            },
            "mediaType": {
              "type": "string",
              "minLength": 1
            },
            "content": {
              "type": "string"
            }
          }
        }
      },
      "domBindings": []
    },
    {
      "id": "copy-seed",
      "title": "Copy active seed",
      "description": "Copy the active deterministic palette seed to the system clipboard.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "write-clipboard"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "client-sensitive",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-operation='copy-seed']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='copy-seed']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once to copy the active seed.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "Read the live announcement/Copied feedback. Clipboard writes do not advance the palette revision; the clipboard can fail or be permission-gated."
    },
    {
      "id": "copy-share-link",
      "title": "Copy share link",
      "description": "Copy the exact-state share URL to the system clipboard.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "write-clipboard"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "client-sensitive",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-operation='copy-share-link']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='copy-share-link']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once to copy the exact-state share URL.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "Read the live announcement/Copied feedback. Clipboard writes do not advance the palette revision; the clipboard can fail or be permission-gated."
    },
    {
      "id": "open-qr-share",
      "title": "Open QR share",
      "description": "Open the dialog containing the exact-state share QR code.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "open-dialog"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-operation='open-qr-share']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='open-qr-share']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once to open the QR dialog.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "Verify the named drawer/dialog is visible and focus has entered it. No palette revision is required."
    },
    {
      "id": "start-fresh",
      "title": "Start fresh",
      "description": "Discard invalid share parameters and intentionally create a new ready palette.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-palette",
        "mutate-presentation",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "error"
      ],
      "domBindings": [
        {
          "surface": "shared",
          "selector": "[data-agent-operation='start-fresh']"
        }
      ],
      "domInstructions": "Click once on the error recovery screen to discard malformed share parameters.",
      "preconditions": [
        "Root status=error; the recovery button is visible."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "set-harmony",
      "title": "Set harmony",
      "description": "Regenerate unlocked colors using a harmony.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "harmony": {
            "enum": [
              "auto",
              "monochromatic",
              "analogous",
              "accented-analogous",
              "complementary",
              "split-complementary",
              "double-split-complementary",
              "triadic",
              "tetradic",
              "square",
              "compound",
              "neutral-accent"
            ]
          }
        },
        "required": [
          "harmony"
        ]
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": true,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='set-harmony']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='set-harmony']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Select input.harmony on the bound select and dispatch its normal change event.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "decrease-color-count",
      "title": "Fewer colors",
      "description": "Drop the last color while preserving retained colors.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='decrease-color-count']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='decrease-color-count']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once when enabled; the lower limit is two colors.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "Disabled controls are unavailable in the current state; do not force a click."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "increase-color-count",
      "title": "More colors",
      "description": "Add one color while preserving existing colors.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-action='increase-color-count']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-action='increase-color-count']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once when enabled; the upper limit is eight colors.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "Disabled controls are unavailable in the current state; do not force a click."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "set-role-color",
      "title": "Edit role color",
      "description": "Set and lock one role to an exact hex; regenerate unlocked partners and reset the primary role to Glow.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "role": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ]
          },
          "hex": {
            "type": "string",
            "pattern": "^\\s*#?[0-9a-fA-F]{6}\\s*$"
          }
        },
        "required": [
          "role",
          "hex"
        ]
      },
      "effects": [
        "mutate-palette",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-operation='set-role-color']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='set-role-color']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Match data-agent-role to role, fill the hex input, then press Enter or blur to commit. Input alone is a draft. The native color picker is outside this binding.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first."
      ],
      "completion": "After commit, read the field aria-invalid and root error attributes. On success, verify the seed or role hex in the handoff. Rejection or an unchanged value does not advance revision. Live colors change immediately; History records the final palette only after 20 seconds of idle color controls. Poll root data-huejoy-history-pending for History completion."
    },
    {
      "id": "undo",
      "title": "Undo palette change",
      "description": "Cancel a pending manual color edit, leave a Saved preview, or restore the previous History entry.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-palette",
        "mutate-presentation",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-operation='undo']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='undo']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once when the bound button is enabled.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "Disabled controls are unavailable in the current state; do not force a click."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    },
    {
      "id": "redo",
      "title": "Redo palette change",
      "description": "Leave a Saved preview or restore the next History entry.",
      "inputSchema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {}
      },
      "effects": [
        "mutate-palette",
        "mutate-presentation",
        "mutate-session-context"
      ],
      "readOnly": false,
      "idempotent": false,
      "confirmation": "none",
      "availableWhen": [
        "ready"
      ],
      "domBindings": [
        {
          "surface": "desktop",
          "selector": "[data-agent-operation='redo']"
        },
        {
          "surface": "mobile",
          "selector": "[data-agent-operation='redo']",
          "prerequisite": "open-tools"
        }
      ],
      "domInstructions": "Click once when the bound button is enabled.",
      "preconditions": [
        "Root ready=true; choose a visible enabled binding.",
        "On mobile, open-tools first.",
        "Disabled controls are unavailable in the current state; do not force a click.",
        "Unavailable while a manual color edit is pending."
      ],
      "completion": "Re-read the current handoff and verify the requested value/selection. An unchanged value is a successful no-op and may not emit an event."
    }
  ],
  "schemas": {
    "agentExport": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "schemaVersion",
        "seed",
        "manifestId",
        "colors",
        "gradientOrder",
        "pattern",
        "direction",
        "gradientCss",
        "cssText"
      ],
      "properties": {
        "schemaVersion": {
          "const": "huejoy/agent-export/2"
        },
        "seed": {
          "type": "string"
        },
        "manifestId": {
          "type": "string"
        },
        "colors": {
          "type": "array",
          "minItems": 2,
          "maxItems": 8,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "role",
              "name",
              "hex",
              "locked"
            ],
            "properties": {
              "role": {
                "enum": [
                  "glow",
                  "anchor",
                  "bridge",
                  "tone-4",
                  "tone-5",
                  "tone-6",
                  "tone-7",
                  "tone-8"
                ]
              },
              "name": {
                "type": "string"
              },
              "hex": {
                "type": "string",
                "pattern": "^#[0-9A-F]{6}$"
              },
              "locked": {
                "type": "boolean"
              }
            }
          },
          "prefixItems": [
            {
              "properties": {
                "role": {
                  "const": "glow"
                }
              }
            },
            {
              "properties": {
                "role": {
                  "const": "anchor"
                }
              }
            },
            {
              "properties": {
                "role": {
                  "const": "bridge"
                }
              }
            },
            {
              "properties": {
                "role": {
                  "const": "tone-4"
                }
              }
            },
            {
              "properties": {
                "role": {
                  "const": "tone-5"
                }
              }
            },
            {
              "properties": {
                "role": {
                  "const": "tone-6"
                }
              }
            },
            {
              "properties": {
                "role": {
                  "const": "tone-7"
                }
              }
            },
            {
              "properties": {
                "role": {
                  "const": "tone-8"
                }
              }
            }
          ]
        },
        "gradientOrder": {
          "type": "array",
          "minItems": 2,
          "maxItems": 8,
          "items": {
            "enum": [
              "glow",
              "anchor",
              "bridge",
              "tone-4",
              "tone-5",
              "tone-6",
              "tone-7",
              "tone-8"
            ]
          },
          "uniqueItems": true
        },
        "pattern": {
          "enum": [
            "radial",
            "conic",
            "double-radial",
            "wide-radial"
          ]
        },
        "direction": {
          "enum": [
            "down",
            "diagonal",
            "across",
            "up"
          ]
        },
        "gradientCss": {
          "type": "string"
        },
        "cssText": {
          "type": "string"
        }
      }
    },
    "agentHandoff": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$defs": {
        "role": {
          "enum": [
            "glow",
            "anchor",
            "bridge",
            "tone-4",
            "tone-5",
            "tone-6",
            "tone-7",
            "tone-8"
          ]
        },
        "error": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "code",
            "message",
            "recoverable"
          ],
          "properties": {
            "code": {
              "enum": [
                "AMBIGUOUS_SHARE_TOKEN",
                "MALFORMED_SHARE_TOKEN",
                "UNSUPPORTED_SHARE_VERSION",
                "INVALID_LEGACY_STATE",
                "INVALID_STATE",
                "NOT_READY",
                "INVALID_INPUT",
                "STALE_REVISION",
                "INDEX_OUT_OF_RANGE",
                "STORAGE_UNAVAILABLE",
                "EXPORT_UNAVAILABLE",
                "ABORTED",
                "CORRUPT_SHARE_TOKEN"
              ]
            },
            "message": {
              "type": "string",
              "minLength": 1
            },
            "recoverable": {
              "type": "boolean"
            },
            "recoveryOperation": {
              "enum": [
                "start-fresh",
                "retry"
              ]
            }
          }
        },
        "sessionContext": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "pageUrl",
            "selection",
            "activeRole"
          ],
          "properties": {
            "pageUrl": {
              "type": "string",
              "format": "uri"
            },
            "selection": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "kind",
                "index"
              ],
              "properties": {
                "kind": {
                  "enum": [
                    "history",
                    "saved"
                  ]
                },
                "index": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "activeRole": {
              "$ref": "#/$defs/role"
            }
          }
        },
        "portableState": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "schemaVersion",
            "codec",
            "stateToken",
            "shareUrl",
            "seed",
            "colors",
            "gradientOrder",
            "pattern",
            "direction",
            "generatorVersion",
            "colorCount",
            "harmony"
          ],
          "properties": {
            "schemaVersion": {
              "const": "huejoy/portable-palette/1"
            },
            "codec": {
              "enum": [
                "hj1",
                "hj2",
                "hj3"
              ]
            },
            "stateToken": {
              "type": "string",
              "pattern": "^hj[123]\\.",
              "maxLength": 360
            },
            "shareUrl": {
              "type": "string",
              "format": "uri"
            },
            "seed": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            },
            "colors": {
              "type": "array",
              "items": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "role",
                  "hex",
                  "locked"
                ],
                "properties": {
                  "role": {
                    "enum": [
                      "glow",
                      "anchor",
                      "bridge",
                      "tone-4",
                      "tone-5",
                      "tone-6",
                      "tone-7",
                      "tone-8"
                    ]
                  },
                  "hex": {
                    "type": "string",
                    "pattern": "^#[0-9A-F]{6}$"
                  },
                  "locked": {
                    "type": "boolean"
                  }
                }
              },
              "minItems": 2,
              "maxItems": 8,
              "prefixItems": [
                {
                  "properties": {
                    "role": {
                      "const": "glow"
                    }
                  }
                },
                {
                  "properties": {
                    "role": {
                      "const": "anchor"
                    }
                  }
                },
                {
                  "properties": {
                    "role": {
                      "const": "bridge"
                    }
                  }
                },
                {
                  "properties": {
                    "role": {
                      "const": "tone-4"
                    }
                  }
                },
                {
                  "properties": {
                    "role": {
                      "const": "tone-5"
                    }
                  }
                },
                {
                  "properties": {
                    "role": {
                      "const": "tone-6"
                    }
                  }
                },
                {
                  "properties": {
                    "role": {
                      "const": "tone-7"
                    }
                  }
                },
                {
                  "properties": {
                    "role": {
                      "const": "tone-8"
                    }
                  }
                }
              ]
            },
            "gradientOrder": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/role"
              },
              "minItems": 2,
              "maxItems": 8,
              "uniqueItems": true
            },
            "pattern": {
              "enum": [
                "radial",
                "conic",
                "double-radial",
                "wide-radial"
              ]
            },
            "direction": {
              "enum": [
                "down",
                "diagonal",
                "across",
                "up"
              ]
            },
            "generatorVersion": {
              "enum": [
                "0.3.0",
                "0.4.0",
                "0.5.0"
              ]
            },
            "colorCount": {
              "type": "integer",
              "minimum": 2,
              "maximum": 8
            },
            "harmony": {
              "enum": [
                "auto",
                "monochromatic",
                "analogous",
                "accented-analogous",
                "complementary",
                "split-complementary",
                "double-split-complementary",
                "triadic",
                "tetradic",
                "square",
                "compound",
                "neutral-accent"
              ]
            },
            "rotation": {
              "type": "integer",
              "minimum": 0,
              "maximum": 359
            }
          }
        },
        "glowColor": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "role",
            "hex",
            "locked"
          ],
          "properties": {
            "role": {
              "const": "glow"
            },
            "hex": {
              "type": "string",
              "pattern": "^#[0-9A-F]{6}$"
            },
            "locked": {
              "type": "boolean"
            }
          }
        },
        "anchorColor": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "role",
            "hex",
            "locked"
          ],
          "properties": {
            "role": {
              "const": "anchor"
            },
            "hex": {
              "type": "string",
              "pattern": "^#[0-9A-F]{6}$"
            },
            "locked": {
              "type": "boolean"
            }
          }
        },
        "bridgeColor": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "role",
            "hex",
            "locked"
          ],
          "properties": {
            "role": {
              "const": "bridge"
            },
            "hex": {
              "type": "string",
              "pattern": "^#[0-9A-F]{6}$"
            },
            "locked": {
              "type": "boolean"
            }
          }
        }
      },
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "schemaVersion",
            "revision",
            "status",
            "portableState",
            "sessionContext"
          ],
          "properties": {
            "schemaVersion": {
              "const": "huejoy/agent-handoff/1"
            },
            "revision": {
              "type": "integer",
              "minimum": 1
            },
            "status": {
              "const": "ready"
            },
            "portableState": {
              "$ref": "#/$defs/portableState"
            },
            "sessionContext": {
              "$ref": "#/$defs/sessionContext"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "schemaVersion",
            "revision",
            "status",
            "error",
            "sessionContext"
          ],
          "properties": {
            "schemaVersion": {
              "const": "huejoy/agent-handoff/1"
            },
            "revision": {
              "type": "integer",
              "minimum": 1
            },
            "status": {
              "const": "error"
            },
            "error": {
              "$ref": "#/$defs/error"
            },
            "sessionContext": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "pageUrl"
              ],
              "properties": {
                "pageUrl": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          }
        }
      ]
    },
    "operationResult": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$defs": {
        "error": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "code",
            "message",
            "recoverable"
          ],
          "properties": {
            "code": {
              "enum": [
                "AMBIGUOUS_SHARE_TOKEN",
                "MALFORMED_SHARE_TOKEN",
                "UNSUPPORTED_SHARE_VERSION",
                "INVALID_LEGACY_STATE",
                "INVALID_STATE",
                "NOT_READY",
                "INVALID_INPUT",
                "STALE_REVISION",
                "INDEX_OUT_OF_RANGE",
                "STORAGE_UNAVAILABLE",
                "EXPORT_UNAVAILABLE",
                "ABORTED",
                "CORRUPT_SHARE_TOKEN"
              ]
            },
            "message": {
              "type": "string",
              "minLength": 1
            },
            "recoverable": {
              "type": "boolean"
            },
            "recoveryOperation": {
              "enum": [
                "start-fresh",
                "retry"
              ]
            }
          }
        }
      },
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "ok",
            "revision",
            "value"
          ],
          "properties": {
            "ok": {
              "const": true
            },
            "revision": {
              "type": "integer",
              "minimum": 1
            },
            "value": {}
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "ok",
            "revision",
            "error"
          ],
          "properties": {
            "ok": {
              "const": false
            },
            "revision": {
              "type": "integer",
              "minimum": 1
            },
            "error": {
              "$ref": "#/$defs/error"
            }
          }
        }
      ]
    }
  },
  "protocolSupport": {
    "browser": {
      "supported": true,
      "authentication": "No account required. State and Saved belong to the current browser."
    },
    "a2a": {
      "supported": false,
      "discoveryStatus": 404,
      "discoveryPaths": [
        "/.well-known/agent-card.json",
        "/.well-known/agent.json"
      ],
      "transport": null,
      "streaming": false
    },
    "remoteMcp": {
      "supported": false
    }
  }
}
