{
  "openapi": "3.1.0",
  "info": {
    "title": "Metrix.Bar Local API",
    "version": "0.0.0",
    "description": "Metrix.Bar local control and data API for AI agents and automation scripts to manage dashboards: create, update source, read snapshots, configure inputs and secrets, refresh, and dispatch events. Listens only on 127.0.0.1. Requests with an Origin header return 403. The Host header must be a loopback IP or localhost, optionally with a port. CORS is disabled. All routes except GET /v0/health require Authorization: Bearer <token>. Request bodies are limited to 2 MiB."
  },
  "servers": [
    {
      "url": "http://127.0.0.1:{port}",
      "description": "Loopback listener; use the address shown in Agent settings",
      "variables": {
        "port": {
          "default": "6387"
        }
      }
    }
  ],
  "tags": [
    {
      "name": "meta"
    },
    {
      "name": "dashboards"
    },
    {
      "name": "inputs"
    }
  ],
  "paths": {
    "/v0/health": {
      "get": {
        "tags": [
          "meta"
        ],
        "summary": "Check API health without authentication",
        "description": "Unauthenticated availability check returning status, protocol version, uptime, and optional app version.",
        "security": [],
        "operationId": "health",
        "responses": {
          "200": {
            "description": "Service available",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "uptime_ms",
                    "protocol_version"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok"
                      ]
                    },
                    "uptime_ms": {
                      "type": "integer",
                      "description": "Milliseconds since process startup"
                    },
                    "protocol_version": {
                      "type": "string",
                      "enum": [
                        "0"
                      ]
                    },
                    "app_version": {
                      "type": "string",
                      "description": "App version; omitted when not configured"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v0/dashboards": {
      "get": {
        "tags": [
          "dashboards"
        ],
        "summary": "List dashboard instance summaries",
        "operationId": "listDashboards",
        "responses": {
          "200": {
            "description": "Dashboard summaries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "dashboards"
                  ],
                  "properties": {
                    "dashboards": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DashboardSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "dashboards"
        ],
        "summary": "Create a dashboard",
        "description": "Content-Type is required and may include a charset parameter. Send raw .bar source as text/plain or application/octet-stream; for application/json, use {\"source\":\"...\"}. Parse failures return 422 with diagnostics. Returns 501 when the application creation callback is unavailable.",
        "operationId": "createDashboard",
        "requestBody": {
          "required": true,
          "content": {
            "text/plain": {
              "schema": {
                "$ref": "#/components/schemas/BarSource"
              }
            },
            "application/octet-stream": {
              "schema": {
                "$ref": "#/components/schemas/BarSource"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SourceBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created; ETag identifies the new source",
            "headers": {
              "Location": {
                "description": "Resource path of the new dashboard",
                "schema": {
                  "type": "string"
                }
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardSummary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v0/dashboards/{id}": {
      "get": {
        "tags": [
          "dashboards"
        ],
        "summary": "Read a dashboard snapshot",
        "description": "Returns status, error, inputs, and view without secret values. The view projects the latest successful UI tree, or null before the first successful render. Event handlers such as onClick are opaque to API clients and are always null.",
        "operationId": "getDashboard",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardView"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "dashboards"
        ],
        "summary": "Uninstall a dashboard",
        "description": "Stops the instance and removes its record and credential-store secrets. Registry-installed files move to a backup directory for reinstallation; local files remain in place.",
        "operationId": "deleteDashboard",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "responses": {
          "204": {
            "description": "Uninstalled with no response body"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v0/dashboards/{id}/source": {
      "get": {
        "tags": [
          "dashboards"
        ],
        "summary": "Read dashboard .bar source",
        "description": "Returns text/plain source and a quoted ETag derived from the first 16 SHA-256 hex characters.",
        "operationId": "getSource",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "responses": {
          "200": {
            "description": ".bar source",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/BarSource"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      },
      "put": {
        "tags": [
          "dashboards"
        ],
        "summary": "Replace dashboard .bar source",
        "description": "If-Match uses strong comparison against a quoted tag list or a standalone \"*\". Weak tags never match; bare tags or malformed lists return 400. Without If-Match, tag checking is skipped but concurrent saves remain protected. A mismatch returns 412; overlapping dashboard operations or saves return 409. The source id must match the path id. Parse failures return 422 with diagnostics. Preflights scheduled(initial) and render before activation. Runtime preflight failures may return 500 while the previous instance keeps running. External effects such as network requests and storage writes cannot be rolled back. File replacement is not a full filesystem transaction; writes through an already-open handle to the old inode cannot always be detected. If the original path is occupied during recovery, a same-directory .bar-recovery-* backup is retained without overwriting the new file.",
        "operationId": "putSource",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "text/plain": {
              "schema": {
                "$ref": "#/components/schemas/BarSource"
              }
            },
            "application/octet-stream": {
              "schema": {
                "$ref": "#/components/schemas/BarSource"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SourceBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated; ETag identifies the new source",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "updated"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "updated": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "description": "If-Match does not match the current source ETag",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v0/dashboards/{id}/settings": {
      "patch": {
        "tags": [
          "dashboards"
        ],
        "summary": "Update dashboard placements and opening modes",
        "operationId": "patchSettings",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "minProperties": 1,
                "additionalProperties": false,
                "properties": {
                  "placements": {
                    "type": [
                      "array",
                      "null"
                    ],
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "enum": [
                        "menubar",
                        "sidebar-left",
                        "sidebar-right",
                        "sidebar-bottom"
                      ]
                    },
                    "description": "Omit to keep the override; null follows dashboard defaults; an empty array disables all entries."
                  },
                  "open_mode": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "flyout",
                      "dialog",
                      null
                    ],
                    "description": "Omit to keep the override; null follows the dashboard default for programmatic opening and sources without an override."
                  },
                  "open_modes": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "additionalProperties": false,
                    "description": "Omit to keep source overrides; null or an empty object clears them. An object replaces all source overrides.",
                    "properties": {
                      "menubar": {
                        "type": "string",
                        "enum": [
                          "flyout",
                          "dialog"
                        ]
                      },
                      "sidebar-left": {
                        "type": "string",
                        "enum": [
                          "flyout",
                          "dialog"
                        ]
                      },
                      "sidebar-right": {
                        "type": "string",
                        "enum": [
                          "flyout",
                          "dialog"
                        ]
                      },
                      "sidebar-bottom": {
                        "type": "string",
                        "enum": [
                          "flyout",
                          "dialog"
                        ]
                      },
                      "shortcut": {
                        "type": "string",
                        "enum": [
                          "flyout",
                          "dialog"
                        ]
                      }
                    }
                  }
                }
              },
              "examples": {
                "sidebar": {
                  "value": {
                    "placements": [
                      "sidebar-left"
                    ],
                    "open_mode": "dialog"
                  }
                },
                "defaults": {
                  "value": {
                    "placements": null,
                    "open_mode": null,
                    "open_modes": null
                  }
                },
                "perSource": {
                  "value": {
                    "placements": [
                      "menubar",
                      "sidebar-right"
                    ],
                    "open_mode": "flyout",
                    "open_modes": {
                      "shortcut": "dialog",
                      "sidebar-right": "dialog"
                    }
                  }
                },
                "noEntries": {
                  "value": {
                    "placements": []
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "placements",
                    "open_mode",
                    "open_modes"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "placements": {
                      "type": "array",
                      "uniqueItems": true,
                      "items": {
                        "type": "string",
                        "enum": [
                          "menubar",
                          "sidebar-left",
                          "sidebar-right",
                          "sidebar-bottom"
                        ]
                      }
                    },
                    "open_mode": {
                      "type": "string",
                      "enum": [
                        "flyout",
                        "dialog"
                      ]
                    },
                    "open_modes": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "menubar",
                        "sidebar-left",
                        "sidebar-right",
                        "sidebar-bottom",
                        "shortcut"
                      ],
                      "description": "Effective opening mode for every configurable source, including disabled entries.",
                      "properties": {
                        "menubar": {
                          "type": "string",
                          "enum": [
                            "flyout",
                            "dialog"
                          ]
                        },
                        "sidebar-left": {
                          "type": "string",
                          "enum": [
                            "flyout",
                            "dialog"
                          ]
                        },
                        "sidebar-right": {
                          "type": "string",
                          "enum": [
                            "flyout",
                            "dialog"
                          ]
                        },
                        "sidebar-bottom": {
                          "type": "string",
                          "enum": [
                            "flyout",
                            "dialog"
                          ]
                        },
                        "shortcut": {
                          "type": "string",
                          "enum": [
                            "flyout",
                            "dialog"
                          ]
                        }
                      }
                    }
                  }
                },
                "example": {
                  "id": "abc",
                  "placements": [
                    "menubar",
                    "sidebar-right"
                  ],
                  "open_mode": "flyout",
                  "open_modes": {
                    "menubar": "flyout",
                    "sidebar-left": "flyout",
                    "sidebar-right": "dialog",
                    "sidebar-bottom": "flyout",
                    "shortcut": "dialog"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v0/dashboards/{id}/inputs": {
      "get": {
        "tags": [
          "inputs"
        ],
        "summary": "List declared inputs and current values",
        "description": "Returns the declared inputs with name, type, required flag, current value, and set status. Secret inputs expose only is_set and always have a null value. File values are path strings.",
        "operationId": "listInputs",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "responses": {
          "200": {
            "description": "Declared inputs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "inputs"
                  ],
                  "properties": {
                    "inputs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Input"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "tags": [
          "inputs"
        ],
        "summary": "Update ordinary input values",
        "description": "Merges input values and schedules an asynchronous inputs-changed refresh without waiting for rendering. Values must match their declared types. Omitted fields keep their current values. Optional string/file inputs can be cleared with an empty string and optional integer/number inputs with null; these explicit clears persist across source reloads and restarts without restoring defaults. Required inputs reject null and empty strings. Secret inputs must use PUT /v0/dashboards/{id}/secrets/{name}. Undeclared keys return 400.",
        "operationId": "updateInputs",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "inputs"
                ],
                "properties": {
                  "inputs": {
                    "type": "object",
                    "description": "Input names mapped to values matching the declared types. string/file require strings; bool requires a boolean, integer requires an integer-valued number, and number requires a finite number. Optional integer/number inputs also accept null as an explicit cleared value; optional string/file inputs accept empty strings. Required inputs reject null and empty strings. Secret inputs are not accepted here.",
                    "additionalProperties": true,
                    "minProperties": 1
                  }
                }
              },
              "example": {
                "inputs": {
                  "host": "plausible.io",
                  "limit": 10
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Accepted and refresh dispatched with no response body"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v0/dashboards/{id}/refresh": {
      "post": {
        "tags": [
          "dashboards"
        ],
        "summary": "Refresh a dashboard",
        "description": "Dispatches a refresh and immediately returns 202 without waiting for rendering.",
        "operationId": "refreshDashboard",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted with no response body"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v0/dashboards/{id}/events/{name}": {
      "post": {
        "tags": [
          "dashboards"
        ],
        "summary": "Dispatch an event to a dashboard Worker",
        "description": "Calls the Worker event export with the optional JSON body as payload. Rendering follows successful event handling. Returns 202 without waiting for completion.",
        "operationId": "postEvent",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "Event name passed to the Worker event handler",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Any JSON payload; an empty body produces null.",
          "content": {
            "application/json": {
              "schema": true
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted with no response body"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          }
        }
      }
    },
    "/v0/dashboards/{id}/secrets/{name}": {
      "put": {
        "tags": [
          "inputs"
        ],
        "summary": "Store a secret input in the system credential store",
        "description": "Stores the secret and triggers a refresh so the script can read the new value. Secret values are excluded from ordinary inputs, stored dashboard records, snapshots, and API responses. The input must be declared as type secret; otherwise returns 404.",
        "operationId": "putSecret",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "Name of a declared secret input",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "value"
                ],
                "properties": {
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Plaintext secret written directly to the system credential store"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Secret stored and refresh dispatched with no response body"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v0/validate": {
      "post": {
        "tags": [
          "meta"
        ],
        "summary": "Validate .bar source without saving",
        "description": "Parses without installing and returns {valid, diagnostics[]}. The parser stops at the first error, so diagnostics has at most one item. The code and path identify the source location, such as \"inputs/input@type\", to help correct the source.",
        "operationId": "validateSource",
        "requestBody": {
          "required": true,
          "content": {
            "text/plain": {
              "schema": {
                "$ref": "#/components/schemas/BarSource"
              }
            },
            "application/octet-stream": {
              "schema": {
                "$ref": "#/components/schemas/BarSource"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SourceBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result with diagnostics when valid is false",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "valid",
                    "diagnostics"
                  ],
                  "properties": {
                    "valid": {
                      "type": "boolean"
                    },
                    "diagnostics": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Diagnostic"
                      },
                      "maxItems": 1
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          }
        }
      }
    },
    "/v0/check": {
      "post": {
        "tags": [
          "meta"
        ],
        "summary": "Check a dashboard in an isolated Worker",
        "operationId": "checkSource",
        "description": "Does not install or modify instances. Executes real JavaScript and network/file I/O allowed by declared permissions. Without fixtures, secrets and desktop integrations are unavailable. Cache and localStorage use temporary directories removed after the check. Optionally runs scheduled(initial), then render if preceding steps succeed. Each hook has a 15-second timeout and supports request cancellation. Module initialization has a separate maximum of 15 seconds; cancellation is checked before and after loading. External effects cannot be rolled back. Diagnostic failures still return 200.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check result; tree=true includes a view with all callback identifiers hidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v0/types": {
      "get": {
        "tags": [
          "meta"
        ],
        "summary": "Export the same TypeScript declarations as the CLI",
        "operationId": "getTypes",
        "responses": {
          "200": {
            "description": "metrixbar.d.ts returned without saving to disk",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "example": "attachment; filename=\"metrixbar.d.ts\""
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v0/dashboards/{id}/reload": {
      "post": {
        "tags": [
          "dashboards"
        ],
        "summary": "Reload saved source after Worker preflight",
        "description": "No request body. Rebuilds the module and preflights scheduled/render, while refresh only fetches data. Failures preserve the old instance; external effects cannot be rolled back.",
        "operationId": "reloadDashboard",
        "parameters": [
          {
            "$ref": "#/components/parameters/DashboardId"
          }
        ],
        "responses": {
          "200": {
            "description": "Reloaded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "reloaded"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "reloaded": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "description": "Application reported an ETag conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Local API token generated and persisted by the app from 32 random bytes encoded as hex. GET /v0/health requires no authentication."
      }
    },
    "parameters": {
      "DashboardId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Dashboard instance ID",
        "schema": {
          "type": "string"
        }
      },
      "IfMatch": {
        "name": "If-Match",
        "in": "header",
        "required": false,
        "description": "Optimistic concurrency using the quoted ETag from GET source or a comma-separated list of quoted tags. Uses strong comparison; weak tags do not match, and bare tags or malformed lists return 400. A standalone \"*\" matches any existing source. Omission skips tag checking but still protects concurrent file saves.",
        "schema": {
          "type": "string"
        }
      }
    },
    "headers": {
      "ETag": {
        "description": "Quoted entity tag derived from the first 16 SHA-256 hex characters of the source",
        "schema": {
          "type": "string"
        },
        "example": "\"0123456789abcdef\""
      }
    },
    "schemas": {
      "CheckRequest": {
        "type": "object",
        "required": [
          "source"
        ],
        "properties": {
          "source": {
            "type": "string",
            "minLength": 1,
            "pattern": "\\S",
            "description": "Nonblank .bar source"
          },
          "inputs": {
            "type": "object",
            "additionalProperties": true,
            "default": {},
            "description": "Ordinary inputs merged in order of defaults then fixture.inputs then request inputs; the inputs object cannot be null, secret inputs are rejected, and optional integer/number values may be null to override defaults with an explicit cleared value"
          },
          "scheduled": {
            "type": "boolean",
            "default": false
          },
          "tree": {
            "type": "boolean",
            "default": false
          },
          "fixture": {
            "type": "object",
            "required": [
              "now"
            ],
            "additionalProperties": false,
            "description": "Isolated development data limited to 2 MiB; now is required. Replaces network, files, secrets, named icons, and clock. Unmatched I/O including images fails; permissions still apply and no live network or resource cache is used.",
            "properties": {
              "now": {
                "type": "string",
                "format": "date-time"
              },
              "inputs": {
                "type": "object",
                "additionalProperties": true
              },
              "icons": {
                "type": "object",
                "description": "SVG or image data URI matched by Icon.name or Image.name without src/svg; each entry is 1..256 KiB and bypasses system icon loading",
                "additionalProperties": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 262144
                }
              },
              "secrets": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "files": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "http": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "url",
                    "body"
                  ],
                  "properties": {
                    "method": {
                      "type": "string",
                      "default": "GET"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "request_body": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "default": 200
                    },
                    "headers": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    },
                    "body": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "screenshot": {
            "type": "object",
            "required": [
              "theme"
            ],
            "additionalProperties": false,
            "properties": {
              "theme": {
                "type": "string",
                "enum": [
                  "light",
                  "dark"
                ]
              },
              "width": {
                "type": "integer",
                "minimum": 1,
                "maximum": 2048,
                "description": "DIP; defaults to view width"
              },
              "height": {
                "type": "integer",
                "minimum": 1,
                "maximum": 2048,
                "description": "DIP; defaults to view height"
              },
              "scale": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 4,
                "default": 1,
                "description": "Total pixels must not exceed 16 Mi"
              }
            }
          }
        }
      },
      "CheckResult": {
        "type": "object",
        "required": [
          "valid",
          "diagnostics"
        ],
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Diagnostic"
                },
                {
                  "type": "object",
                  "required": [
                    "path"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "parse",
                        "inputs",
                        "module",
                        "scheduled",
                        "render",
                        "native_props",
                        "resources",
                        "fixture",
                        "screenshot"
                      ]
                    }
                  }
                }
              ]
            }
          },
          "screenshot": {
            "type": "object",
            "required": [
              "mime_type",
              "width",
              "height",
              "data_base64"
            ],
            "properties": {
              "mime_type": {
                "type": "string",
                "const": "image/png"
              },
              "width": {
                "type": "integer",
                "description": "Actual PNG pixel width"
              },
              "height": {
                "type": "integer",
                "description": "Actual PNG pixel height"
              },
              "data_base64": {
                "type": "string",
                "contentEncoding": "base64"
              }
            }
          },
          "view": {
            "description": "Present only when tree=true; handlers are null and the view is null when unavailable",
            "anyOf": [
              {
                "$ref": "#/components/schemas/View"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "BarSource": {
        "type": "string",
        "description": "Declarative XML-style .bar dashboard source"
      },
      "SourceBody": {
        "type": "object",
        "required": [
          "source"
        ],
        "properties": {
          "source": {
            "type": "string",
            "minLength": 1,
            "description": ".bar source text"
          }
        }
      },
      "Diagnostic": {
        "type": "object",
        "required": [
          "severity",
          "code",
          "message"
        ],
        "properties": {
          "severity": {
            "type": "string",
            "enum": [
              "error"
            ]
          },
          "code": {
            "type": "string",
            "description": "Error code; validate uses the parse path such as bar@id or invalid. Check uses a stage such as parse/inputs/module/scheduled/render/native_props."
          },
          "message": {
            "type": "string"
          },
          "path": {
            "type": "string",
            "description": "Source location, script stage, or native component property path when available"
          }
        }
      },
      "DashboardSummary": {
        "type": "object",
        "required": [
          "id",
          "status",
          "protocol_version"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "revision": {
            "type": "integer",
            "description": "Snapshot revision incremented on each commit; omitted when zero"
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "title": {
            "type": "string"
          },
          "protocol_version": {
            "type": "string",
            "enum": [
              "0"
            ],
            "description": ".bar protocol version"
          },
          "version": {
            "type": "string",
            "description": "Optional dashboard code version independent of the app version"
          },
          "icon": {
            "type": "string",
            "description": "Image reference URL, data URI, or named icon; metadata only"
          },
          "description": {
            "type": "string"
          },
          "docs": {
            "type": "string",
            "description": "Optional plain-text setup instructions preserving internal newlines"
          },
          "license": {
            "type": "string",
            "description": "Optional license declaration such as an SPDX identifier; omission grants no open-source license"
          },
          "homepage": {
            "type": "string",
            "description": "Developer homepage"
          },
          "etag": {
            "type": "string",
            "description": "Raw unquoted entity tag of the current source"
          }
        }
      },
      "DashboardView": {
        "type": "object",
        "required": [
          "id",
          "status",
          "updated_at",
          "revision",
          "inputs",
          "view"
        ],
        "properties": {
          "docs": {
            "type": "string",
            "description": "Optional plain-text setup instructions preserving internal newlines"
          },
          "id": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "error": {
            "type": "string",
            "description": "Latest runtime error; present when status is error"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "revision": {
            "type": "integer",
            "description": "Snapshot revision incremented on every successful or failed commit"
          },
          "inputs": {
            "type": "object",
            "additionalProperties": true,
            "description": "Committed ordinary input values without secrets"
          },
          "view": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/View"
              },
              {
                "type": "null"
              }
            ],
            "description": "Latest successfully rendered UI tree or null before a successful render"
          }
        }
      },
      "Status": {
        "type": "string",
        "enum": [
          "idle",
          "loading",
          "ok",
          "error"
        ],
        "description": "idle means not yet run while hidden and not being viewed; refresh or events wake it. loading means no successful render yet. error means the latest run failed and view retains the last successful tree."
      },
      "Input": {
        "type": "object",
        "required": [
          "name",
          "type",
          "required",
          "value",
          "is_set"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "string",
              "integer",
              "number",
              "bool",
              "secret",
              "file",
              "select"
            ]
          },
          "required": {
            "type": "boolean"
          },
          "label": {
            "type": "string"
          },
          "help": {
            "type": "string"
          },
          "value": {
            "description": "Current or default value; null for secrets or cleared optional numeric inputs, and a path string (possibly empty) for files"
          },
          "is_set": {
            "type": "boolean",
            "description": "Whether a non-null value exists (including empty strings); false for explicitly cleared numeric inputs, and indicates a credential-store entry for secrets"
          }
        }
      },
      "View": {
        "type": "object",
        "required": [
          "tray",
          "panel"
        ],
        "properties": {
          "tray": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string"
              },
              "icon": {
                "type": "string"
              },
              "iconTemplate": {
                "type": "boolean"
              },
              "tooltip": {
                "type": "string"
              },
              "menu": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MenuItem"
                }
              }
            }
          },
          "panel": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Node"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "MenuItem": {
        "type": "object",
        "required": [
          "onClick"
        ],
        "properties": {
          "label": {
            "type": "string"
          },
          "onClick": {
            "type": "null",
            "description": "JavaScript handlers are opaque to API clients and always null"
          },
          "disabled": {
            "type": "boolean"
          },
          "separator": {
            "type": "boolean"
          },
          "checked": {
            "type": "boolean"
          },
          "radio": {
            "type": "boolean"
          },
          "shortcut": {
            "type": "string"
          },
          "tooltip": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MenuItem"
            }
          }
        }
      },
      "Node": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Native component type name such as Column/Row/Text/Meter"
          },
          "text": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "props": {
            "type": "object",
            "additionalProperties": true,
            "description": "Component properties; handlers and menu callbacks are projected as null"
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Node"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message from the HTTP error response"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Missing or malformed request body or invalid fields",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid Bearer token; scheme is case-insensitive and token matching is exact",
        "headers": {
          "WWW-Authenticate": {
            "schema": {
              "type": "string"
            },
            "description": "Bearer realm=\"Metrix.Bar\""
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "missing": {
                "value": {
                  "error": "missing bearer token"
                }
              },
              "invalid": {
                "value": {
                  "error": "invalid bearer token"
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Origin header present including Origin: null, or Host is not a loopback IP or localhost",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "origin": {
                "value": {
                  "error": "origin not allowed"
                }
              },
              "host": {
                "value": {
                  "error": "host not allowed"
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Dashboard or secret input not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationFailed": {
        "description": ".bar parsing failed with structured diagnostics",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "error",
                "diagnostics"
              ],
              "properties": {
                "error": {
                  "type": "string",
                  "enum": [
                    "validation failed"
                  ]
                },
                "diagnostics": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Diagnostic"
                  },
                  "maxItems": 1
                }
              }
            }
          }
        }
      },
      "NotImplemented": {
        "description": "Required application callback is unavailable",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal server error without internal details",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Dashboard already exists or another operation on it is in progress",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Request body exceeds 2 MiB",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "Unsupported request Content-Type",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ]
}
