{
  "openapi": "3.1.0",
  "info": {
    "title": "BondGraph Studio — Simulation API",
    "version": "1.0.0",
    "summary": "Run a Bond Graph (BGIF v1) model on the edge and return the time-series result as JSON.",
    "description": "Public, no-auth, CORS-open HTTP API for simulating bond graph models.\n\nThe same simulator that powers the in-browser editor (BDF-1 / BDF-2\nwith optional adaptive stepping, mode-switching, and event resets)\nruns on the request path. Designed for AI agents and external tools.\n\n**Discoverability hops**\n- `GET /api/public/simulate` (no params) returns a self-describing usage doc.\n- `GET /api/public/openapi.json` (this document) is the machine-readable spec.\n- `GET /llms.txt` is the agent-readable site index.\n- `/docs#api` is the human-readable description.",
    "contact": {
      "name": "BondGraph Studio",
      "url": "https://xn--lda.se/docs#api"
    },
    "license": {
      "name": "See project repository"
    }
  },
  "servers": [
    {
      "url": "https://xn--lda.se",
      "description": "This deployment"
    },
    {
      "url": "https://xn--lda.se",
      "description": "Production (custom domain)"
    },
    {
      "url": "https://bondgraph-creator.lovable.app",
      "description": "Production (lovable.app)"
    }
  ],
  "paths": {
    "/api/public/simulate": {
      "get": {
        "summary": "Run a simulation (GET, query-param form)",
        "description": "Pass a URL-encoded BGIF document in the `bgif` query param. Suitable for small models (URL ≲ 8 KB on most clients). Omit `bgif` to get a JSON usage doc.",
        "operationId": "simulateGet",
        "parameters": [
          {
            "name": "bgif",
            "in": "query",
            "required": false,
            "description": "URL-encoded JSON. Either a bare BGIF document `{bgifVersion,components,systems}` or the `{bgif,layout}` wrapper saved by the editor. Omit to receive the self-describing usage doc.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "startTime",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "default": 0
            }
          },
          {
            "name": "endTime",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "default": 10
            }
          },
          {
            "name": "stepSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "default": 0.01,
              "exclusiveMinimum": 0
            }
          },
          {
            "name": "solver",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "bdf1",
                "bdf2"
              ],
              "default": "bdf2"
            }
          },
          {
            "name": "tolerance",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "minimum": 0
            },
            "description": ">0 enables adaptive internal stepping; output is interpolated onto the `stepSize` grid."
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "full",
                "compact"
              ],
              "default": "full"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Simulation result, or self-describing usage doc when `bgif` is omitted.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SimulationResult"
                    },
                    {
                      "$ref": "#/components/schemas/UsageDoc"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (invalid JSON, missing bgif, bad config values).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResult"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Run a simulation (POST, JSON body — recommended)",
        "description": "No URL-length cap; preferred for non-trivial models.",
        "operationId": "simulatePost",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Simulation result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResult"
                }
              }
            }
          }
        }
      },
      "options": {
        "summary": "CORS preflight",
        "operationId": "simulateOptions",
        "responses": {
          "204": {
            "description": "No content; CORS headers set."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "BGIF": {
        "title": "Bond Graph Interchange Format (BGIF)",
        "type": "object",
        "required": [
          "bgifVersion",
          "components",
          "systems"
        ],
        "additionalProperties": false,
        "properties": {
          "bgifVersion": {
            "type": "string",
            "description": "Semantic version of the BGIF document format itself.",
            "pattern": "^\\d+\\.\\d+(\\.\\d+)?$",
            "default": "1.0.0"
          },
          "components": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BGIF/definitions/component"
            }
          },
          "systems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BGIF/definitions/system"
            }
          },
          "layout": {
            "$ref": "#/components/schemas/BGIF/definitions/layout",
            "description": "Optional editor-only view state: element positions, sizes, per-port angle overrides, workflow, and model metadata."
          }
        },
        "definitions": {
          "component": {
            "type": "object",
            "required": [
              "id",
              "ports"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string",
                "description": "Display name; falls back to id."
              },
              "description": {
                "type": "string"
              },
              "library": {
                "type": "string",
                "description": "UI grouping (top-level library)."
              },
              "group": {
                "type": "string",
                "description": "UI sub-group within a library."
              },
              "fidelity": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "default": "medium"
              },
              "ports": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BGIF/definitions/port"
                }
              },
              "parameters": {
                "type": "object",
                "additionalProperties": {
                  "$ref": "#/components/schemas/BGIF/definitions/parameter"
                }
              },
              "models": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "low": {
                    "$ref": "#/components/schemas/BGIF/definitions/bg_model"
                  },
                  "medium": {
                    "$ref": "#/components/schemas/BGIF/definitions/bg_model"
                  },
                  "high": {
                    "$ref": "#/components/schemas/BGIF/definitions/bg_model"
                  }
                }
              },
              "portMap": {
                "type": "object",
                "description": "Maps each outer port id to an inner element + port id. Required for the simulator to flatten subsystem instances.",
                "additionalProperties": {
                  "type": "object",
                  "required": [
                    "innerElementId",
                    "innerPortId"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "innerElementId": {
                      "type": "string"
                    },
                    "innerPortId": {
                      "type": "string"
                    }
                  }
                }
              },
              "variableAliases": {
                "type": "object",
                "description": "Maps raw inner-variable names (e.g. q_C_zone) to friendlier display labels.",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "icon": {
                "$ref": "#/components/schemas/BGIF/definitions/icon"
              }
            }
          },
          "port": {
            "type": "object",
            "required": [
              "id"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "domain": {
                "type": "string",
                "enum": [
                  "thermal",
                  "fluid",
                  "electrical",
                  "mechanical",
                  "magnetic",
                  "chemical",
                  "generic"
                ]
              },
              "direction": {
                "type": "string",
                "enum": [
                  "in",
                  "out",
                  "bidirectional"
                ],
                "default": "bidirectional"
              },
              "effort": {
                "type": "string",
                "description": "Effort variable name (e.g. voltage, pressure, temperature)."
              },
              "flow": {
                "type": "string",
                "description": "Flow variable name (e.g. current, volumetric flow, entropy flow)."
              },
              "side": {
                "type": "string",
                "enum": [
                  "top",
                  "right",
                  "bottom",
                  "left"
                ],
                "description": "Edge of the icon the port attaches to (legacy placement)."
              },
              "offset": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Relative position along `side`, 0–1."
              },
              "angle": {
                "description": "Explicit angular position on the outline. Compass string (N|NE|E|SE|S|SW|W|NW) or numeric bearing 0–360° clockwise from North.",
                "oneOf": [
                  {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 360
                  },
                  {
                    "type": "string",
                    "enum": [
                      "N",
                      "NE",
                      "E",
                      "SE",
                      "S",
                      "SW",
                      "W",
                      "NW"
                    ]
                  }
                ]
              }
            }
          },
          "parameter": {
            "type": "object",
            "required": [
              "type"
            ],
            "additionalProperties": false,
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "number",
                  "integer",
                  "string",
                  "boolean",
                  "expression"
                ]
              },
              "default": {},
              "unit": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "min": {
                "type": "number"
              },
              "max": {
                "type": "number"
              },
              "enum": {
                "type": "array",
                "items": {
                  "type": [
                    "string",
                    "number"
                  ]
                }
              }
            }
          },
          "bg_model": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "elements": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BGIF/definitions/bg_element"
                }
              },
              "junctions": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BGIF/definitions/junction"
                }
              },
              "bonds": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BGIF/definitions/bond"
                }
              }
            }
          },
          "bg_element": {
            "type": "object",
            "required": [
              "id",
              "type"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "R",
                  "C",
                  "I",
                  "Se",
                  "Sf",
                  "TF",
                  "GY",
                  "annotation"
                ]
              },
              "text": {
                "type": "string",
                "description": "Annotation body (LaTeX-capable). Only meaningful when type=annotation."
              },
              "fontSize": {
                "type": "number",
                "description": "Override label/text font size in px."
              },
              "parameters": {
                "type": "object",
                "additionalProperties": {}
              }
            }
          },
          "junction": {
            "type": "object",
            "required": [
              "id",
              "type"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "0",
                  "1"
                ]
              }
            }
          },
          "bond": {
            "type": "object",
            "required": [
              "from",
              "to"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "from": {
                "type": "string",
                "description": "Element id, optionally `element.port`."
              },
              "to": {
                "type": "string",
                "description": "Element id, optionally `element.port`."
              },
              "fromPort": {
                "type": "string",
                "description": "Explicit source port id (overrides `from`'s dot suffix)."
              },
              "toPort": {
                "type": "string",
                "description": "Explicit target port id (overrides `to`'s dot suffix)."
              },
              "causality": {
                "type": "string",
                "enum": [
                  "auto",
                  "effort",
                  "flow",
                  "none"
                ],
                "default": "auto",
                "description": "`none` preserves an explicit user choice of no causal stroke; `auto` means unassigned."
              },
              "causalityFixed": {
                "type": "boolean",
                "default": false
              }
            }
          },
          "icon": {
            "type": "object",
            "required": [
              "svg"
            ],
            "additionalProperties": false,
            "properties": {
              "svg": {
                "type": "string",
                "description": "Inner SVG markup (children of a <g>, no surrounding <svg> tag). Sanitized on import."
              },
              "viewBox": {
                "type": "string",
                "default": "0 0 100 100"
              },
              "portPositions": {
                "type": "object",
                "additionalProperties": {
                  "$ref": "#/components/schemas/BGIF/definitions/position"
                }
              }
            }
          },
          "position": {
            "type": "object",
            "required": [
              "x",
              "y"
            ],
            "additionalProperties": false,
            "properties": {
              "x": {
                "type": "number"
              },
              "y": {
                "type": "number"
              }
            }
          },
          "system": {
            "type": "object",
            "required": [
              "id",
              "instances",
              "connections"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "metadata": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "author": {
                    "type": "string"
                  },
                  "created": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "modified": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "description": {
                    "type": "string"
                  }
                }
              },
              "causalityStrategy": {
                "type": "string",
                "enum": [
                  "auto",
                  "preferStorage",
                  "strict"
                ],
                "default": "auto"
              },
              "instances": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BGIF/definitions/instance"
                }
              },
              "connections": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BGIF/definitions/connection"
                }
              },
              "variableAliases": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "defaultSimulation": {
                "$ref": "#/components/schemas/BGIF/definitions/simulationConfig"
              },
              "workflow": {
                "$ref": "#/components/schemas/BGIF/definitions/workflow"
              }
            }
          },
          "instance": {
            "type": "object",
            "required": [
              "id",
              "component"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "type": "string"
              },
              "component": {
                "type": "string"
              },
              "fidelity": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ]
              },
              "parameters": {
                "type": "object",
                "additionalProperties": {}
              }
            }
          },
          "connection": {
            "type": "object",
            "required": [
              "from",
              "to"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "from": {
                "type": "string",
                "description": "`instanceId.portId`."
              },
              "to": {
                "type": "string",
                "description": "`instanceId.portId`."
              },
              "causality": {
                "type": "string",
                "enum": [
                  "auto",
                  "effort",
                  "flow",
                  "none"
                ],
                "default": "auto"
              },
              "causalityFixed": {
                "type": "boolean",
                "default": false
              }
            }
          },
          "simulationConfig": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "startTime": {
                "type": "number"
              },
              "endTime": {
                "type": "number"
              },
              "stepSize": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "solver": {
                "type": "string",
                "enum": [
                  "bdf1",
                  "bdf2"
                ]
              },
              "tolerance": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "timeUnit": {
                "type": "string",
                "enum": [
                  "s",
                  "min",
                  "h",
                  "day"
                ]
              }
            }
          },
          "workflow": {
            "type": "object",
            "required": [
              "currentStage"
            ],
            "additionalProperties": false,
            "properties": {
              "currentStage": {
                "type": "string",
                "enum": [
                  "design",
                  "validation",
                  "simulation",
                  "analysis",
                  "report"
                ]
              },
              "history": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "stage",
                    "enteredAt"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "stage": {
                      "type": "string",
                      "enum": [
                        "design",
                        "validation",
                        "simulation",
                        "analysis",
                        "report"
                      ]
                    },
                    "enteredAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "note": {
                      "type": "string"
                    },
                    "user": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "layout": {
            "type": "object",
            "description": "Editor view-state extension. Not required for simulation; preserves visual layout across round-trips.",
            "additionalProperties": false,
            "properties": {
              "elements": {
                "type": "object",
                "description": "Keyed by instance id.",
                "additionalProperties": {
                  "type": "object",
                  "required": [
                    "x",
                    "y",
                    "width",
                    "height"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "x": {
                      "type": "number"
                    },
                    "y": {
                      "type": "number"
                    },
                    "width": {
                      "type": "number"
                    },
                    "height": {
                      "type": "number"
                    },
                    "fontSize": {
                      "type": "number"
                    }
                  }
                }
              },
              "portAngles": {
                "type": "object",
                "description": "Per-instance, per-port angle override. Compass string or numeric bearing.",
                "additionalProperties": {
                  "type": "object",
                  "additionalProperties": {
                    "oneOf": [
                      {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 360
                      },
                      {
                        "type": "string",
                        "enum": [
                          "N",
                          "NE",
                          "E",
                          "SE",
                          "S",
                          "SW",
                          "W",
                          "NW"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "BGIFWrapper": {
        "type": "object",
        "description": "Wrapper produced by the editor’s Save action. Either field may be passed directly as the `bgif` request field; layout is ignored by the simulator.",
        "required": [
          "bgif"
        ],
        "properties": {
          "bgif": {
            "$ref": "#/components/schemas/BGIF"
          },
          "layout": {
            "type": "object",
            "additionalProperties": true,
            "description": "Editor-only layout metadata (positions, port angles). Ignored on the API."
          }
        }
      },
      "SimulationConfig": {
        "type": "object",
        "description": "Subset of the in-app SimulationConfig accepted by the API.",
        "additionalProperties": false,
        "properties": {
          "startTime": {
            "type": "number",
            "default": 0
          },
          "endTime": {
            "type": "number",
            "default": 10
          },
          "stepSize": {
            "type": "number",
            "default": 0.01,
            "exclusiveMinimum": 0
          },
          "solver": {
            "type": "string",
            "enum": [
              "bdf1",
              "bdf2"
            ],
            "default": "bdf2"
          },
          "tolerance": {
            "type": "number",
            "minimum": 0,
            "description": ">0 enables adaptive internal stepping."
          }
        }
      },
      "SimulateRequest": {
        "type": "object",
        "required": [
          "bgif"
        ],
        "additionalProperties": false,
        "properties": {
          "bgif": {
            "description": "Either a BGIF document or the editor wrapper.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/BGIF"
              },
              {
                "$ref": "#/components/schemas/BGIFWrapper"
              }
            ]
          },
          "config": {
            "$ref": "#/components/schemas/SimulationConfig"
          },
          "format": {
            "type": "string",
            "enum": [
              "full",
              "compact"
            ],
            "default": "full"
          }
        }
      },
      "SimulationResult": {
        "type": "object",
        "required": [
          "status",
          "time",
          "variables",
          "meta"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "error"
            ]
          },
          "error": {
            "type": "string",
            "description": "Present when status=\"error\"."
          },
          "time": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Sample times in seconds."
          },
          "variables": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "number"
              }
            },
            "description": "Named time-series traces. Conventional names: q_<C-label> (C displacements), p_<I-label> (I momenta), e_<from>_<to> / f_<from>_<to> for per-bond effort/flow. Flattened subsystem states use a dot, e.g. \"q_Thermal Zone.C_zone\"."
          },
          "meta": {
            "type": "object",
            "required": [
              "variableCount",
              "sampleCount",
              "config",
              "durationMs"
            ],
            "properties": {
              "modelId": {
                "type": "string"
              },
              "modelName": {
                "type": "string"
              },
              "variableCount": {
                "type": "integer"
              },
              "sampleCount": {
                "type": "integer"
              },
              "config": {
                "$ref": "#/components/schemas/SimulationConfig"
              },
              "durationMs": {
                "type": "integer",
                "description": "Wall-clock cost of this call."
              }
            }
          }
        }
      },
      "ErrorResult": {
        "type": "object",
        "required": [
          "status",
          "error"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "error"
            ]
          },
          "error": {
            "type": "string"
          }
        }
      },
      "UsageDoc": {
        "type": "object",
        "description": "Self-describing JSON returned when /api/public/simulate is called without a bgif param.",
        "additionalProperties": true
      }
    }
  },
  "tags": [
    {
      "name": "simulate",
      "description": "BondGraph simulation endpoints"
    }
  ]
}