{
  "asyncapi": "3.0.0",
  "info": {
    "title": "OverMox Real-time Event Stream",
    "version": "1.0.0",
    "description": "Server-pushed event stream over SignalR/WebSocket. Clients subscribe by calling Subscribe(eventTypes) on the hub at /api/events; the server broadcasts EventEnvelope messages as they fire. Generated from .sync-registry.yaml; do not hand-edit. Run `python -m tools.sync fix` to regenerate."
  },
  "servers": {
    "default": {
      "host": "localhost:5000",
      "pathname": "/api/events",
      "protocol": "ws",
      "description": "SignalR hub. Wire protocol is WebSocket."
    }
  },
  "channels": {
    "eventStream": {
      "address": "/api/events",
      "description": "Bidirectional channel. Server pushes EventEnvelope messages.",
      "messages": {
        "ConsoleLog": {
          "$ref": "#/components/messages/ConsoleLog"
        },
        "GraphRunning": {
          "$ref": "#/components/messages/GraphRunning"
        },
        "GraphStopped": {
          "$ref": "#/components/messages/GraphStopped"
        },
        "MidiInput": {
          "$ref": "#/components/messages/MidiInput"
        },
        "NodeDone": {
          "$ref": "#/components/messages/NodeDone"
        },
        "NodeExecuting": {
          "$ref": "#/components/messages/NodeExecuting"
        },
        "OvermoxConnected": {
          "$ref": "#/components/messages/OvermoxConnected"
        },
        "OvermoxDisconnected": {
          "$ref": "#/components/messages/OvermoxDisconnected"
        },
        "PortsUpdated": {
          "$ref": "#/components/messages/PortsUpdated"
        },
        "ProcessExited": {
          "$ref": "#/components/messages/ProcessExited"
        },
        "ProcessLoaded": {
          "$ref": "#/components/messages/ProcessLoaded"
        },
        "ProjectClosed": {
          "$ref": "#/components/messages/ProjectClosed"
        },
        "ProjectOpened": {
          "$ref": "#/components/messages/ProjectOpened"
        },
        "StreamingEvent": {
          "$ref": "#/components/messages/StreamingEvent"
        },
        "TweenCompleted": {
          "$ref": "#/components/messages/TweenCompleted"
        },
        "VariableChanged": {
          "$ref": "#/components/messages/VariableChanged"
        },
        "VariableDeleted": {
          "$ref": "#/components/messages/VariableDeleted"
        },
        "WebhookReceived": {
          "$ref": "#/components/messages/WebhookReceived"
        }
      }
    }
  },
  "operations": {
    "receiveEvents": {
      "action": "receive",
      "channel": {
        "$ref": "#/channels/eventStream"
      },
      "messages": [
        {
          "$ref": "#/channels/eventStream/messages/ConsoleLog"
        },
        {
          "$ref": "#/channels/eventStream/messages/GraphRunning"
        },
        {
          "$ref": "#/channels/eventStream/messages/GraphStopped"
        },
        {
          "$ref": "#/channels/eventStream/messages/MidiInput"
        },
        {
          "$ref": "#/channels/eventStream/messages/NodeDone"
        },
        {
          "$ref": "#/channels/eventStream/messages/NodeExecuting"
        },
        {
          "$ref": "#/channels/eventStream/messages/OvermoxConnected"
        },
        {
          "$ref": "#/channels/eventStream/messages/OvermoxDisconnected"
        },
        {
          "$ref": "#/channels/eventStream/messages/PortsUpdated"
        },
        {
          "$ref": "#/channels/eventStream/messages/ProcessExited"
        },
        {
          "$ref": "#/channels/eventStream/messages/ProcessLoaded"
        },
        {
          "$ref": "#/channels/eventStream/messages/ProjectClosed"
        },
        {
          "$ref": "#/channels/eventStream/messages/ProjectOpened"
        },
        {
          "$ref": "#/channels/eventStream/messages/StreamingEvent"
        },
        {
          "$ref": "#/channels/eventStream/messages/TweenCompleted"
        },
        {
          "$ref": "#/channels/eventStream/messages/VariableChanged"
        },
        {
          "$ref": "#/channels/eventStream/messages/VariableDeleted"
        },
        {
          "$ref": "#/channels/eventStream/messages/WebhookReceived"
        }
      ]
    }
  },
  "components": {
    "messages": {
      "ConsoleLog": {
        "name": "console.log",
        "title": "Console Log",
        "summary": "Fires when a console log entry is created in OverMox.",
        "x-streaming-facing": true,
        "description": "Returns the log message text, severity type, and timestamp. Streamed for real-time observability of script and graph execution.\n\n*Example: When the audio level peaks above -3dB, log the spike for later replay analysis.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "console.log"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/ConsoleLogData"
            }
          }
        }
      },
      "GraphRunning": {
        "name": "graph.running",
        "title": "Graph Running",
        "summary": "Fires when a graph starts executing.",
        "x-streaming-facing": true,
        "description": "Returns the graphId of the graph that started. The graph runs until graph.stopped fires or POST /api/graphs/{id}/stop is called.\n\n*Example: When a viewer subscribes, run a confetti-spawning graph.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "graph.running"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/GraphRunningData"
            }
          }
        }
      },
      "GraphStopped": {
        "name": "graph.stopped",
        "title": "Graph Stopped",
        "summary": "Fires when a graph stops executing.",
        "x-streaming-facing": true,
        "description": "Returns the graphId of the graph that stopped. Pairs with graph.running to track full execution lifecycle for any subscribed graph.\n\n*Example: When stream ends, listen for graph.stopped on the intro graph and queue the outro.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "graph.stopped"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/GraphStoppedData"
            }
          }
        }
      },
      "MidiInput": {
        "name": "midi.input",
        "title": "Midi Input",
        "summary": "Fires when a MIDI input message arrives from a connected device.",
        "x-streaming-facing": true,
        "description": "Returns the MIDI status byte, two data bytes, and channel. Routed from any MIDI device the runtime is currently listening on; multiple devices share the same event stream.\n\nPer-MIDI-type extras (note/velocity/channel for note-on/note-off, control/value/channel for control-change, value/channel for pitch-bend, program/channel for program-change) are merged into the payload at runtime; see CommandExecutor.cs:4418-4453 for the dispatch logic. Phase K declares only the fixed-base keys (subscriptionId, device, eventType, timestamp) for AsyncAPI consumers; a future phase can introduce a discriminator mechanism if consumers require typed extensions.\n\n*Example: When the audio level peaks above -3dB, fade in the chorus VFX.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "midi.input"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/MidiInputData"
            }
          }
        }
      },
      "NodeDone": {
        "name": "node.done",
        "title": "Node Done",
        "summary": "Fires when a node finishes executing.",
        "x-streaming-facing": true,
        "description": "Returns the nodeId of the node that finished. Pairs with node.executing to trace per-node execution timing across a running graph.\n\n*Example: When chat says '!step', advance the queued sequence after node.done fires on the previous step.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "node.done"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/NodeDoneData"
            }
          }
        }
      },
      "NodeExecuting": {
        "name": "node.executing",
        "title": "Node Executing",
        "summary": "Fires when a node begins executing.",
        "x-streaming-facing": true,
        "description": "Returns the nodeId of the node that started. Useful for visualising live graph execution flow or driving a heads-up display of which node currently holds the cursor.\n\n*Example: When a viewer cheers 100 bits, highlight the receiving node as soon as node.executing fires for it.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "node.executing"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/NodeExecutingData"
            }
          }
        }
      },
      "OvermoxConnected": {
        "name": "overmox.connected",
        "title": "Overmox Connected",
        "summary": "Fires when the OverMox runtime connects to the Controller.",
        "x-streaming-facing": false,
        "description": "Returns the project metadata for the connected OverMox instance. Marks the start of the connection lifecycle; downstream subscribers may now query scene, graph, and runtime state.",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "overmox.connected"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/OvermoxConnectedData"
            }
          }
        }
      },
      "OvermoxDisconnected": {
        "name": "overmox.disconnected",
        "title": "Overmox Disconnected",
        "summary": "Fires when the OverMox runtime disconnects from the Controller.",
        "x-streaming-facing": false,
        "description": "No payload. Marks the end of the connection lifecycle; downstream subscribers should treat any cached scene, graph, or runtime state as stale until a fresh overmox.connected event arrives.",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "overmox.disconnected"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/OvermoxDisconnectedData"
            }
          }
        }
      },
      "PortsUpdated": {
        "name": "ports.updated",
        "title": "Ports Updated",
        "summary": "Fires when one or more port values change.",
        "x-streaming-facing": false,
        "description": "Returns an array of port records, each with id, current value, and type. Multiple changes in the same tick are batched into one event so subscribers can debounce updates by the natural runtime tick boundary.",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "ports.updated"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/PortsUpdatedData"
            }
          }
        }
      },
      "ProcessExited": {
        "name": "process.exited",
        "title": "Process Exited",
        "summary": "Fires when a process started via process.start exits.",
        "x-streaming-facing": true,
        "description": "Returns the processId, processName, and exitCode. Pairs with process.loaded to track full lifecycle for any process launched through POST /api/actions/process/start; subscribers filter by processId to react to a specific child.\n\n*Example: When the donation-overlay process crashes, listen for process.exited with the matching processId and queue an automatic relaunch graph.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "process.exited"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/ProcessExitedData"
            }
          }
        }
      },
      "ProcessLoaded": {
        "name": "process.loaded",
        "title": "Process Loaded",
        "summary": "Fires when a process started via process.start finishes loading.",
        "x-streaming-facing": true,
        "description": "Returns the processId, processName, and startTime as an ISO-8601 string. Marks the point at which the operating system reports the launched process as initialised; subscribers filter by processId to gate downstream work on a specific child.\n\n*Example: When a viewer redeems a \"spawn the visualizer\" reward, wait for process.loaded with the new processId before sending input commands to the freshly launched window.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "process.loaded"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/ProcessLoadedData"
            }
          }
        }
      },
      "ProjectClosed": {
        "name": "project.closed",
        "title": "Project Closed",
        "summary": "Fires when the current project closes.",
        "x-streaming-facing": false,
        "description": "No payload. Marks the project lifecycle end; subscribers should release any project-scoped resources and wait for the next project.opened event before resuming project-tied work.",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "project.closed"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/ProjectClosedData"
            }
          }
        }
      },
      "ProjectOpened": {
        "name": "project.opened",
        "title": "Project Opened",
        "summary": "Fires when a project opens.",
        "x-streaming-facing": false,
        "description": "Returns the project metadata for the newly opened project. Marks the start of the project lifecycle; subscribers may now query graphs, variables, and assets that belong to the project.",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "project.opened"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/ProjectOpenedData"
            }
          }
        }
      },
      "StreamingEvent": {
        "name": "streaming.event",
        "title": "Streaming Event",
        "summary": "Fires when a streaming-platform event arrives (chat command, donation, subscriber alert, bits cheer, raid).",
        "x-streaming-facing": true,
        "description": "Returns the eventType label, source provider name, and the provider-specific data block. Bridges Twitch, YouTube, StreamElements, and StreamLabs into one stream so graphs can react without per-provider plumbing.\n\nPer-provider eventData fields are merged into the payload via foreach at CommandExecutor.cs:6312-6325; Phase K declares only the fixed-base keys (subscriptionId, platform, eventType, timestamp) for AsyncAPI consumers.\n\n*Example: When chat says '!confetti', spawn a confetti graph.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "streaming.event"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/StreamingEventData"
            }
          }
        }
      },
      "TweenCompleted": {
        "name": "tween.completed",
        "title": "Tween Completed",
        "summary": "Fires when a tween animation reaches its end state.",
        "x-streaming-facing": true,
        "description": "Returns the tween identifier and the target object reference. Lets subscribers chain follow-up actions to the exact moment a tween settles, rather than guessing duration.\n\n*Example: When a viewer subscribes, tween a banner from offscreen to centre, then trigger the next graph step on tween.completed.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "tween.completed"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/TweenCompletedData"
            }
          }
        }
      },
      "VariableChanged": {
        "name": "variable.changed",
        "title": "Variable Changed",
        "summary": "Fires when a variable value changes.",
        "x-streaming-facing": true,
        "description": "Returns the full variable record (id, name, type, value). Subscribers see every assignment, including ones triggered by other graphs or by external API writes through PUT /api/variables/{id}.\n\n*Example: When a viewer donates over $50, increment the donation-total variable and watch variable.changed update the on-screen counter.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "variable.changed"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/VariableChangedData"
            }
          }
        }
      },
      "VariableDeleted": {
        "name": "variable.deleted",
        "title": "Variable Deleted",
        "summary": "Fires when a variable is deleted.",
        "x-streaming-facing": true,
        "description": "Returns the variableId of the removed variable. Subscribers should clear any cached references to that variable so later reads do not resurface stale state.\n\n*Example: When stream ends, delete the per-session vote-tally variable and let variable.deleted clear viewer overlays.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "variable.deleted"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/VariableDeletedData"
            }
          }
        }
      },
      "WebhookReceived": {
        "name": "webhook.received",
        "title": "Webhook Received",
        "summary": "Fires when an inbound HTTP webhook delivers a payload to /api/webhooks/{name}.",
        "x-streaming-facing": true,
        "description": "Broadcasts the listenerId, the request path, the raw request body as payload (a string), and a timestamp. Routes any external HTTP source (donation services, alert dashboards, custom integrations) into the same event stream as native providers.\n\n*Example: When the donation webhook fires above $100, run the milestone celebration graph.*",
        "payload": {
          "type": "object",
          "required": [
            "Type",
            "Timestamp"
          ],
          "properties": {
            "Type": {
              "type": "string",
              "const": "webhook.received"
            },
            "Timestamp": {
              "type": "string",
              "format": "date-time"
            },
            "Data": {
              "$ref": "#/components/schemas/WebhookReceivedData"
            }
          }
        }
      }
    },
    "schemas": {
      "ConsoleLogData": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "contextType": {
            "type": "string"
          },
          "context": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "notificationMessage": {
            "type": "string"
          }
        }
      },
      "GraphRunningData": {
        "type": "string",
        "format": "uuid"
      },
      "GraphStoppedData": {
        "type": "string",
        "format": "uuid"
      },
      "MidiInputData": {
        "type": "object",
        "properties": {
          "subscriptionId": {
            "type": "string"
          },
          "device": {
            "type": "string"
          },
          "eventType": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "NodeDoneData": {
        "type": "string"
      },
      "NodeExecutingData": {
        "type": "string"
      },
      "OvermoxConnectedData": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string"
          },
          "openScene": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "graphs": {
            "type": "array",
            "items": {}
          },
          "variables": {
            "type": "array",
            "items": {}
          },
          "restServerURL": {
            "type": "string"
          }
        }
      },
      "OvermoxDisconnectedData": {
        "type": "object",
        "description": "Untyped or descriptive payload literal: 'null'"
      },
      "PortsUpdatedData": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "value": {
              "type": "string"
            },
            "type": {
              "type": "string"
            }
          }
        }
      },
      "ProcessExitedData": {
        "type": "object",
        "properties": {
          "processId": {
            "type": "string"
          },
          "processName": {
            "type": "string"
          },
          "exitCode": {
            "type": "string"
          }
        }
      },
      "ProcessLoadedData": {
        "type": "object",
        "properties": {
          "processId": {
            "type": "string"
          },
          "processName": {
            "type": "string"
          },
          "startTime": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProjectClosedData": {
        "type": "object",
        "description": "Untyped or descriptive payload literal: 'null'"
      },
      "ProjectOpenedData": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string"
          },
          "openScene": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "graphs": {
            "type": "array",
            "items": {}
          },
          "variables": {
            "type": "array",
            "items": {}
          },
          "restServerURL": {
            "type": "string"
          }
        }
      },
      "StreamingEventData": {
        "type": "object",
        "properties": {
          "subscriptionId": {
            "type": "string"
          },
          "platform": {
            "type": "string"
          },
          "eventType": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TweenCompletedData": {
        "type": "object",
        "properties": {
          "tweenId": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          },
          "action": {
            "type": "string"
          },
          "duration": {
            "type": "number"
          }
        }
      },
      "VariableChangedData": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "variableType": {
            "type": "string"
          },
          "owningGraph": {
            "type": "string"
          },
          "parentVariableID": {
            "type": "string"
          },
          "arrayVariableArray": {
            "type": "object",
            "additionalProperties": true
          },
          "arrayVariableType": {
            "type": "string"
          },
          "dataValues": {
            "type": "string"
          },
          "genericVariableValue": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "VariableDeletedData": {
        "type": "string",
        "format": "uuid"
      },
      "WebhookReceivedData": {
        "type": "object",
        "properties": {
          "listenerId": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "payload": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}
