{
  "openapi": "3.1.0",
  "info": {
    "title": "Super STT daemon protocol",
    "description": "HTTP/1.1 + JSON over a Unix domain socket at `$XDG_RUNTIME_DIR/stt/super-stt-http.sock` (override with `SUPER_STT_HTTP_SOCKET`). There is no TCP listener: the socket's filesystem permissions are the first layer of access control, and the daemon reads `SO_PEERCRED` on each connection to identify the calling binary.\n\nEvery endpoint except `POST /v1/auth/request` requires `Authorization: Bearer <token>`. A token is minted only after the user approves your app in a consent popup, and is bound to the approved binary — an app cannot widen its own permissions. See `docs/protocol/auth.md`.\n\nBecause the transport is a Unix socket, the `servers` entry below is nominal; point your client at the socket and use any `Host`. With curl:\n\n```\ncurl --unix-socket \"$XDG_RUNTIME_DIR/stt/super-stt-http.sock\" \\\n     -H \"Authorization: Bearer $STT_TOKEN\" \\\n     http://stt.local/v1/ping\n```",
    "contact": {
      "name": "Super STT",
      "url": "https://github.com/jorge-menjivar/super-stt"
    },
    "license": {
      "name": "GPL-3.0-only",
      "identifier": "GPL-3.0-only"
    },
    "version": "0.2.4-beta.1"
  },
  "servers": [
    {
      "url": "http://stt.local",
      "description": "Nominal host; the transport is the Unix socket"
    }
  ],
  "paths": {
    "/v1/auth/request": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "Ask the user for a session token",
        "description": "The consent handshake, and the only endpoint reachable without a token.\n\nThe daemon reads `SO_PEERCRED` on your connection, resolves `/proc/<pid>/exe`, and shows the user a popup naming that binary and the scopes you asked for. On Allow it mints a 32-byte token bound to that binary and valid for 30 days.\n\nA denial is remembered for the `(binary, scopes)` pair for the rest of the daemon's lifetime and answers `403` immediately without re-prompting — renaming your app does not clear it, since the key is the binary. Restarting the daemon does.\n\nSetting `SUPER_STT_AUTO_APPROVE=1` in the daemon's environment skips the popup entirely; it is for tests and CI, not for production.",
        "operationId": "auth_request",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuthRequestBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The user approved. Store the token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthOk"
                }
              }
            }
          },
          "400": {
            "description": "Body was missing or malformed (`invalid_body`), or `scopes` was empty or named an unknown scope (`invalid_scope`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The user denied or dismissed the popup (`user_denied`, `user_dismissed`), a previous denial for this binary and scope set still stands (`user_denied_cached`), the connecting user is not the daemon's own (`uid_mismatch`), the daemon could not resolve your binary and so refused to identify you (`peer_unverifiable`), or the popup could not be shown (`popup_failed`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/status": {
      "get": {
        "tags": [
          "auth"
        ],
        "summary": "Check the held token without prompting",
        "description": "Reports what the presented token is good for, and never opens a consent popup — which is what makes it the right probe for a headless or CLI client. Reaching this handler at all means the token validated.\n\nUse it to fail fast on a token about to expire, rather than discovering it mid-operation.",
        "operationId": "auth_status",
        "responses": {
          "200": {
            "description": "The token is valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthStatusOk"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed — re-run the consent handshake.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": []
          }
        ]
      }
    },
    "/v1/backend/list": {
      "get": {
        "tags": [
          "backends"
        ],
        "summary": "List installed backends",
        "description": "Every backend installed on this machine, each with the models it serves, the options it exposes, and which of its secrets are configured. Secret *values* are never returned — only whether each is set.\n\nThis is the full catalog, roles included. `GET /pipeline/{stage}/model/list` is the narrower read a stage's model picker wants; browsing what is *available to install* is `GET /registry/backend/list`.",
        "operationId": "list_backends",
        "responses": {
          "200": {
            "description": "The installed catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BackendCatalog"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/backend/{backend_id}": {
      "delete": {
        "tags": [
          "backends"
        ],
        "summary": "Uninstall a backend",
        "description": "Removes an installed backend and its files from disk.\n\nIf the backend was filling a pipeline stage, that stage is emptied first: any loaded model is unloaded and the selection cleared, so the daemon does not end up pointing at files that no longer exist. The response says which stages were affected.\n\nRefused with `409 backend_busy` while a recording or realtime session is in flight — removing files out from under one would strand state it still depends on.",
        "operationId": "uninstall_backend",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fwhisper`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fwhisper"
          }
        ],
        "responses": {
          "200": {
            "description": "Removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UninstallResponse"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No installed backend claims that `source`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          },
          "409": {
            "description": "A recording or realtime session is in flight (`backend_busy`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          },
          "500": {
            "description": "The files could not be removed (`remove_failed`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/backend/{backend_id}/option/list": {
      "get": {
        "tags": [
          "backends"
        ],
        "summary": "List a backend's options",
        "description": "Every option this backend declares, each with its label, type, default, and the value actually in effect. This is what a settings UI renders a form from.\n\nOptions are the backend's own configuration — an endpoint URL, a model parameter — declared in its manifest. Credentials are not options; those are secrets, at `/backend/{backend_id}/secret/list`.",
        "operationId": "list_options",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fwhisper`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fwhisper"
          }
        ],
        "responses": {
          "200": {
            "description": "The backend's options.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BackendOptions"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No installed backend has that `source` (`unknown_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/backend/{backend_id}/option/{name}": {
      "get": {
        "tags": [
          "backends"
        ],
        "summary": "Read one option's effective value",
        "description": "The value in effect for a single option, alongside the manifest default so a UI can show what clearing it would revert to.",
        "operationId": "get_option",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fwhisper`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fwhisper"
          },
          {
            "name": "name",
            "in": "path",
            "description": "The option's name, as the backend's manifest declares it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The option's effective value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptionValue"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such backend (`unknown_backend`) or no such option (`unknown_option`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "backends"
        ],
        "summary": "Override an option",
        "description": "Stores a value for this option, overriding the manifest default. Answers with the option's new effective value, so a UI can render the result without a second read.\n\nA `base_url` value is canonicalized before storage, so the field reads back the endpoint that will actually be dialed — the scheme in particular, since whether a request is encrypted should not be invisible in the field the user is looking at. A value that yields no host is stored as typed rather than refused; model load rejects it by name. Every other option is stored verbatim, whitespace included, because it may carry meaning the daemon does not interpret.\n\nA loaded model does not pick this up on its own — reload the stage with `POST /pipeline/{stage}/model/reload`.",
        "operationId": "set_option",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fwhisper`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fwhisper"
          },
          {
            "name": "name",
            "in": "path",
            "description": "The option's name, as the backend's manifest declares it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OptionBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Stored; this is the new effective value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptionValue"
                }
              }
            }
          },
          "400": {
            "description": "The value was empty (`invalid_request`). Use `DELETE` to clear an override.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such backend (`unknown_backend`) or no such option (`unknown_option`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "delete": {
        "tags": [
          "backends"
        ],
        "summary": "Clear an option override",
        "description": "Removes the stored value, reverting the option to the manifest default. Answers with the effective value that results, which is the default when one is declared and `null` when none is.",
        "operationId": "delete_option",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fwhisper`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fwhisper"
          },
          {
            "name": "name",
            "in": "path",
            "description": "The option's name, as the backend's manifest declares it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cleared; this is the value now in effect.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptionValue"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such backend (`unknown_backend`) or no such option (`unknown_option`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/backend/{backend_id}/secret/list": {
      "get": {
        "tags": [
          "backends"
        ],
        "summary": "List a backend's secrets",
        "description": "Every credential this backend declares, with whether each is currently set. **Values are never returned** — not here, not anywhere. They live in the system keyring, and the only operations are write and clear.\n\nThis is a separate scope from `settings` precisely because it is the credential surface: a token granted `settings` cannot reach it.",
        "operationId": "list_secrets",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fopenai`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fopenai"
          }
        ],
        "responses": {
          "200": {
            "description": "The declared secrets and whether each is set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretList"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `secrets` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such backend (`unknown_backend`) or no such secret (`unknown_secret`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "secrets"
            ]
          }
        ]
      }
    },
    "/v1/backend/{backend_id}/secret/{name}": {
      "get": {
        "tags": [
          "backends"
        ],
        "summary": "Check whether one secret is set",
        "description": "Reports existence only. There is no endpoint that returns a stored credential.",
        "operationId": "get_secret",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fopenai`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fopenai"
          },
          {
            "name": "name",
            "in": "path",
            "description": "The secret's name, as the backend's manifest declares it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Whether a value is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretConfigured"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `secrets` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such backend (`unknown_backend`) or no such secret (`unknown_secret`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "secrets"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "backends"
        ],
        "summary": "Store a secret",
        "description": "Writes the credential to the system keyring. It cannot be read back afterwards; only replaced or cleared.\n\nA loaded model does not pick up a new credential on its own — reload the stage with `POST /pipeline/{stage}/model/reload`.",
        "operationId": "set_secret",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fopenai`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fopenai"
          },
          {
            "name": "name",
            "in": "path",
            "description": "The secret's name, as the backend's manifest declares it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SecretBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretConfigured"
                }
              }
            }
          },
          "400": {
            "description": "The value was empty (`invalid_request`). Use `DELETE` to clear a secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `secrets` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such backend (`unknown_backend`) or no such secret (`unknown_secret`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The keyring could not be written (`keyring_unavailable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "secrets"
            ]
          }
        ]
      },
      "delete": {
        "tags": [
          "backends"
        ],
        "summary": "Clear a secret",
        "description": "Removes the stored credential from the keyring, returning the secret to unset. A backend that requires it will refuse to load until one is stored again.",
        "operationId": "delete_secret",
        "parameters": [
          {
            "name": "backend_id",
            "in": "path",
            "description": "The backend's id — its `source` as `GET /backend/list` reports it — percent-encoded, e.g. `github.com%2Facme%2Fopenai`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "github.com%2Facme%2Fopenai"
          },
          {
            "name": "name",
            "in": "path",
            "description": "The secret's name, as the backend's manifest declares it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cleared.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecretConfigured"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `secrets` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such backend (`unknown_backend`) or no such secret (`unknown_secret`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The keyring could not be written (`keyring_unavailable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "secrets"
            ]
          }
        ]
      }
    },
    "/v1/events": {
      "get": {
        "tags": [
          "events"
        ],
        "summary": "Subscribe to the event stream",
        "description": "A Server-Sent Events stream of everything the daemon publishes. The response is `text/event-stream` and stays open until the client disconnects, the daemon shuts down, or the calling binary changes on disk (which emits a final `revoked` frame and invalidates the token).\n\nThe first frame is always `subscribed`, carrying a `client_id` and the topic list that was accepted. A `: keepalive` comment is sent periodically so idle connections are not reaped by intermediaries.\n\n**Scopes are per topic, not per endpoint.** Any valid token reaches this route; the subscription is then refused whole if the token lacks the scope for *any* requested topic, so ask only for what you hold.\n\n| Topic | Scope |\n|---|---|\n| `recording_started`, `recording_stopped`, `recording_state`, `transcribing_started`, `transcribing_stopped` | `recording_events` |\n| `frequency_bands` | `audio_visualization` |\n| `partial_stt`, `final_stt` | `global_transcriptions` |\n| `daemon_status_changed`, `download_progress`, `registry_install` | `daemon_status` |\n\nUnder backpressure the daemon drops frames rather than buffering them without bound; visualization frames are what shed in practice.",
        "operationId": "events",
        "parameters": [
          {
            "name": "topics",
            "in": "query",
            "description": "Comma-separated topic names, at least one. Unknown or empty → `400 invalid_topic`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "recording_state,final_stt"
          }
        ],
        "responses": {
          "200": {
            "description": "The stream is open. Frames follow as `event:`/`data:` pairs.",
            "content": {
              "text/event-stream": {}
            }
          },
          "400": {
            "description": "`topics` was missing, empty, or named a topic that does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the scope for one of the requested topics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": []
          }
        ]
      }
    },
    "/v1/gpu_info": {
      "get": {
        "tags": [
          "hardware"
        ],
        "summary": "Inventory the host's GPUs",
        "description": "What the daemon can see of this machine's accelerators: one entry per detected GPU with its memory, plus the host-wide driver and runtime versions that decide which backend builds will actually run here.\n\nDetection is a live probe, so this reflects the machine now rather than a cached answer. A host with no GPU answers `200` with an empty list.",
        "operationId": "get_gpu_info",
        "responses": {
          "200": {
            "description": "The detected GPUs and host toolchain versions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GpuInventory"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/ping": {
      "get": {
        "tags": [
          "health"
        ],
        "summary": "Liveness probe",
        "description": "Confirms the listener is reachable and the presented token is valid. Introspects no state.\n\nTo check whether the *token* is still good without risking a consent popup, prefer `GET /auth/status` — that is the dedicated probe.",
        "operationId": "ping",
        "responses": {
          "200": {
            "description": "The daemon is up. `message` is always `pong`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                },
                "example": {
                  "message": "pong",
                  "status": "success"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Connection refused — the daemon is over its per-client connection cap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": []
          }
        ]
      }
    },
    "/v1/pipeline": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "Report every pipeline stage",
        "description": "The ordered stages a transcript passes through. Stage 1 turns audio into text; every later stage rewrites what the one before it produced.\n\nEach stage reports the backend filling it and whether the stage is switched on. What that backend is running is one level down, at `GET /pipeline/{stage}/model` — a stage is a durable selection, its model has a runtime, and reporting the two together is what once let the stages drift apart. Stages are addressed by position precisely so a third can be appended without inventing a third endpoint for it.",
        "operationId": "get_pipeline",
        "responses": {
          "200": {
            "description": "Every stage, stage 1 first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineReport"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "Report one pipeline stage",
        "description": "The backend filling this position, and whether the stage is switched on. The same object `GET /pipeline` carries in its array, for a client that only cares about one position — narrowed from that report rather than derived separately, so one stage and the whole list can never disagree.\n\nThe model is not here: read it at `GET /pipeline/{stage}/model`.",
        "operationId": "get_stage",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The stage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "pipeline"
        ],
        "summary": "Select the backend filling a stage",
        "description": "Points a stage at an installed backend. Selecting a backend does not load a model — do that with `POST /pipeline/{stage}/model`.\n\nA backend that serves nothing this stage can run is refused: filling stage 2 with a transcription-only backend would leave the user staring at an empty model picker with no reason given.",
        "operationId": "set_stage_backend",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetBackendBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Selected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageMutation"
                }
              }
            }
          },
          "400": {
            "description": "No installed backend has that `source`, or it serves nothing this stage can run (`invalid_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "delete": {
        "tags": [
          "pipeline"
        ],
        "summary": "Empty a stage",
        "description": "Deselects the stage's backend, unloading its model first if one is up. The stage then does nothing: stage 1 empty means no transcription, stage 2 empty means transcripts pass through unrewritten.",
        "operationId": "clear_stage_backend",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Emptied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageMutation"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/backend/list": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "List the backends that can fill a stage",
        "description": "The installed backends serving at least one model this stage can run, in the shape `GET /backend/list` returns them.\n\nFill a stage's backend picker from this rather than from `GET /backend/list`: a backend serving nothing this stage can run is refused by `POST /pipeline/{stage}`, and offering one hands the user an error to discover by choosing it. A backend serving both roles appears in both stages' lists.\n\nEmpty when nothing installed serves this stage — the state that should read as \"install one\" rather than as an empty dropdown.",
        "operationId": "list_stage_backends",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The backends on offer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BackendCatalog"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/device/list": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "List the devices this stage's backend can run on",
        "description": "The devices the backend filling this stage can run on this host, without naming a model. Use it before a model is chosen; once one is, the per-model list is the narrower and more accurate answer.",
        "operationId": "list_stage_devices",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The devices on offer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceList"
                }
              }
            }
          },
          "400": {
            "description": "The stage has no backend selected (`invalid_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "Report a stage's model",
        "description": "What the stage is pointed at, whether it is loaded, which accelerator it runs on, and the load still in flight.\n\n`model` is the *selection*, not the running instance: it survives an unload, so a card can offer to load the same model again — onto another device, say — without the user picking it a second time. `loaded` is what says whether it is up. The two are separate at every stage; stage 1 collapsed them into one until the stages were made to behave alike.\n\n`device` carries the stored preference and what it resolved to, which is all a picker needs to render its current value. What the model *could* run on is `GET /pipeline/{stage}/model/{model}/device/list`, kept separate because that answer costs a fresh probe of the host's accelerators.",
        "operationId": "get_stage_model",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The stage's model slot. `model` is `null` when nothing is selected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageModelEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "pipeline"
        ],
        "summary": "Run a model in a stage",
        "description": "Loads `model` into the stage, downloading it first if this machine does not have it yet. That download can be long: watch the `download_progress` event topic, or poll `GET /pipeline/{stage}/model` and read `switch`. Abandon it with `POST /pipeline/{stage}/model/cancel`.\n\nOmitting `source` uses the backend already selected for the stage.",
        "operationId": "set_stage_model",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetModelBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Accepted. The model may still be downloading — read `switch` to follow it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageMutation"
                }
              }
            }
          },
          "400": {
            "description": "No such model (`invalid_model`), or no such backend (`invalid_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "delete": {
        "tags": [
          "pipeline"
        ],
        "summary": "Stop a stage's model",
        "description": "Unloads the model, freeing its device memory, and leaves the backend selected so a different model can be loaded without re-selecting it. To empty the stage entirely, use `DELETE /pipeline/{stage}`.",
        "operationId": "clear_stage_model",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Unloaded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageMutation"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model/cancel": {
      "post": {
        "tags": [
          "pipeline"
        ],
        "summary": "Abandon a stage's in-flight load",
        "description": "Stops the download or load this stage has in flight. Scoped to the stage: the stages provision independently, so cancelling one is not a licence to abandon another's download.\n\n`409 no_switch_in_progress` when the stage has nothing in flight.",
        "operationId": "cancel_stage_model",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "Nothing was in flight for this stage (`no_switch_in_progress`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model/list": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "List the models a stage can run",
        "description": "The models the backend filling this stage serves *in this stage's role* — transcription models for stage 1, post-processors for stage 2. Fill a model picker from this.\n\nScoped twice over, and both halves matter. A model from another backend cannot load here; a model with the wrong role loads and then fails on every use, which for a post-processor picked as a transcription model means each recording fails after the user has already spoken.\n\nThe full catalog, every installed backend and every role, is `GET /backend/list`. This is the narrow read a stage's picker wants, and it is answered per stage precisely so a client does not have to re-derive roles for itself.",
        "operationId": "list_stage_models",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The models on offer, `(name, source)` pairs. Empty when the stage has no backend.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelList"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model/reload": {
      "post": {
        "tags": [
          "pipeline"
        ],
        "summary": "Re-instantiate a stage's model in place",
        "description": "Tears the model down and brings it back up so it picks up changed secrets and options — an API key set through `/backend/{backend_id}/secret/list`, say — without the client having to unload and reload by hand.\n\nNothing is re-downloaded; the files on disk are unchanged.",
        "operationId": "reload_stage_model",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Reloaded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model/{model}/device": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "Read a model's device preference",
        "description": "The accelerator this model is set to run on, and — when the preference is the generic `gpu` — what it actually resolved to once loaded. The preference is per model, not per stage: two models in the same stage can prefer different devices.",
        "operationId": "get_model_device",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          },
          {
            "name": "model",
            "in": "path",
            "description": "The model's name, as `GET /pipeline/{stage}/model/list` or `GET /backend/list` spells it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The preference, and what it resolved to.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelDevice"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "pipeline"
        ],
        "summary": "Set a model's device preference",
        "description": "Chooses the accelerator this model runs on. If it is the model the stage is currently running, it is reloaded onto the new device; otherwise the preference is stored and takes effect at the next load.\n\nEvery stage reloads the same way — unload, then load on the new device — and a reload that fails puts the model back on the device it had, leaves the setting as it was, and answers `500` with the reason.\n\nList what this host can offer with `GET /pipeline/{stage}/model/{model}/device/list`.",
        "operationId": "set_model_device",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          },
          {
            "name": "model",
            "in": "path",
            "description": "The model's name, as `GET /pipeline/{stage}/model/list` or `GET /backend/list` spells it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetDeviceBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Preference set; this is the resulting report.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelDevice"
                }
              }
            }
          },
          "400": {
            "description": "This host cannot offer that device (`invalid_device`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "The reload failed; the model was put back on the device it had.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model/{model}/device/list": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "List the devices a model can run on here",
        "description": "What this machine can actually offer this model — the intersection of the host's accelerators and the builds the model ships. Fill a device picker from this rather than from `GET /gpu_info`, which reports the hardware without regard to what the model supports.",
        "operationId": "list_model_devices",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          },
          {
            "name": "model",
            "in": "path",
            "description": "The model's name, as `GET /pipeline/{stage}/model/list` or `GET /backend/list` spells it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The devices on offer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceList"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model/{model}/language": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "Read a model's language override",
        "description": "The language this specific model transcribes in, and what decided it: the per-model override, the global `/settings/language` setting, or the model's own default. Addressed by `(source, model)` rather than \"the active model\", so it can be read whether or not the model is loaded.\n\n`override` is `null` when none is set, which is what \"follows the global setting\" looks like. What the override *may* be set to is `GET /pipeline/{stage}/model/{model}/language/list`.",
        "operationId": "get_model_language",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          },
          {
            "name": "model",
            "in": "path",
            "description": "The model's name, as `GET /pipeline/{stage}/model/list` spells it. Resolved against the backend filling this stage.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "How this model's language resolves.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelLanguageState"
                }
              }
            }
          },
          "400": {
            "description": "The stage has no backend selected, so there is nothing to resolve `model` against (`invalid_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`), or this stage's backend serves no such model (`unknown_model`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "pipeline"
        ],
        "summary": "Set a model's language override",
        "description": "Pins this model to a language regardless of the global `/settings/language` setting. A tag the model does not serve is refused rather than silently ignored.\n\nOverridden in turn by a `language` field in a single `POST /transcribe` body.",
        "operationId": "set_model_language",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          },
          {
            "name": "model",
            "in": "path",
            "description": "The model's name, as `GET /pipeline/{stage}/model/list` spells it. Resolved against the backend filling this stage.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LanguageBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Override set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelLanguageState"
                }
              }
            }
          },
          "400": {
            "description": "The body was empty (`invalid_request`), this model does not serve that language (`unsupported_language`), or the stage has no backend selected (`invalid_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`), or this stage's backend serves no such model (`unknown_model`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "delete": {
        "tags": [
          "pipeline"
        ],
        "summary": "Clear a model's language override",
        "description": "Removes the per-model pin, returning this model to the global `/settings/language` setting.",
        "operationId": "clear_model_language",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          },
          {
            "name": "model",
            "in": "path",
            "description": "The model's name, as `GET /pipeline/{stage}/model/list` spells it. Resolved against the backend filling this stage.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Override cleared.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelLanguageState"
                }
              }
            }
          },
          "400": {
            "description": "The stage has no backend selected (`invalid_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`), or this stage's backend serves no such model (`unknown_model`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/pipeline/{stage}/model/{model}/language/list": {
      "get": {
        "tags": [
          "pipeline"
        ],
        "summary": "List the languages a model can be pinned to",
        "description": "What `POST /pipeline/{stage}/model/{model}/language` will accept for this model: the tags it serves, plus the reserved `auto` for letting it detect the language itself.\n\nFill a language picker from this rather than from a general BCP-47 list — a tag the model does not serve is refused, and offering one is an error the user only discovers by choosing it.\n\nEmpty for a monolingual model, which has nothing to choose however many tags its manifest lists. That is the same shape `GET /pipeline/{stage}/model/{model}/device/list` answers with for a model that runs remotely, and a client hides the control on an empty list rather than special-casing a status.",
        "operationId": "list_model_languages",
        "parameters": [
          {
            "name": "stage",
            "in": "path",
            "description": "Pipeline position: `1` transcribes, `2` post-processes. A position that does not exist is a `404 unknown_stage`.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            },
            "example": 1
          },
          {
            "name": "model",
            "in": "path",
            "description": "The model's name, as `GET /pipeline/{stage}/model/list` spells it. Resolved against the backend filling this stage.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The languages on offer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LanguageList"
                }
              }
            }
          },
          "400": {
            "description": "The stage has no backend selected, so there is nothing to resolve `model` against (`invalid_backend`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such stage (`unknown_stage`), or this stage's backend serves no such model (`unknown_model`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/registry/backend/install": {
      "post": {
        "tags": [
          "registry"
        ],
        "summary": "Install a backend",
        "description": "Installs a backend from the registry, from a git repo, or from a local path — send exactly one of `source`, `repo_url`, or `local_path`.\n\nThe daemon picks the release asset matching this host's architecture and accelerators, and answers `202` as soon as that choice is made: the download itself continues in the background. Follow it on the `registry_install` event topic, keyed by the returned `install_id`. A `warning` means the install proceeded with a caveat worth showing the user.\n\nInstalling neither selects the backend nor loads a model — do that through `/pipeline/{stage}`.",
        "operationId": "install_registry_backend",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InstallRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Accepted; the download runs in the background.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Not exactly one of `source`, `repo_url`, `local_path` (`bad_request`), or no asset matches this host.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No catalog entry for that `source` (`not_found`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          },
          "409": {
            "description": "An install for this backend is already in flight, or a recording is running (`backend_busy`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/registry/backend/list": {
      "get": {
        "tags": [
          "registry"
        ],
        "summary": "Browse the published backend catalog",
        "description": "Every backend published to the registry, with the models each serves and whether this machine can run it. `compatible` is decided against the host's actual accelerators and this Super STT's version, so the list reflects what is installable here rather than what exists in general.\n\n`needs_client_update` separates the two ways a backend can be blocked: a host that lacks the right GPU will never run it, but a Super STT one version behind is something the user can fix in a minute. Surface those differently.\n\nThis is what is *available*; `GET /backend/list` is what is installed.",
        "operationId": "list_registry_backends",
        "parameters": [
          {
            "name": "include_incompatible",
            "in": "query",
            "description": "Include entries this machine cannot run. Off by default, so the catalog\nshows what is actually installable here.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "description": "Filter by backend kind.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "online",
            "in": "query",
            "description": "Filter by whether the backend calls out to a network service.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Case-insensitive substring match over name and description.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The catalog could not be fetched and nothing is cached (`registry_unavailable`). Retry, or force a fetch with `POST /registry/backend/refresh`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/registry/backend/refresh": {
      "post": {
        "tags": [
          "registry"
        ],
        "summary": "Re-fetch the backend catalog",
        "description": "Pulls the published index again rather than serving what is cached, and reports how many backends it now holds. Use it after a backend is published, or to clear an `index_stale` flag.\n\n`GET /registry/backend/list` refreshes on its own schedule; this forces it now.",
        "operationId": "refresh_registry",
        "responses": {
          "200": {
            "description": "Refreshed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefreshResponse"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The catalog could not be fetched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/registry/backend/update": {
      "post": {
        "tags": [
          "registry"
        ],
        "summary": "Update an installed backend",
        "description": "Upgrades an installed backend to the newest version the catalog offers for this host. Answers with the versions moved between; `noop` is `true` when the installed version was already current, which is a success rather than an error.\n\nLike install, the download runs in the background — follow `install_id` on the `registry_install` topic when one is returned.",
        "operationId": "update_registry_backend",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Up to date already, or the upgrade was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateResponse"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No installed backend has that `source` (`not_found`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          },
          "409": {
            "description": "An install is already in flight, or a recording is running (`backend_busy`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryError"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/audio_theme": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read the selected audio cue theme",
        "description": "Answers with the selected theme's token.",
        "operationId": "get_audio_theme",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioThemeState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Select the audio cue theme",
        "description": "Chooses which set of sounds marks the start and end of a recording. List the accepted values with `GET /settings/audio_theme/list`; set the loudness at `/settings/volume`.",
        "operationId": "set_audio_theme",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetAudioThemeBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioThemeState"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/audio_theme/list": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "List the available audio cue themes",
        "description": "Every theme `POST /settings/audio_theme` accepts. The set is fixed in the daemon build, not user-extensible.",
        "operationId": "list_audio_themes",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioThemeList"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/audio_theme/test": {
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Play the selected theme's cues",
        "description": "Plays the start and stop cues once, at the configured volume, so a settings UI can preview a theme without starting a recording. Changes nothing.",
        "operationId": "test_audio_theme",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/custom_models_dir": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read the custom models directory",
        "description": "Answers with the configured path, or `null` when no override is set.",
        "operationId": "get_custom_models_dir",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomModelsDirState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Point the daemon at a models directory of your own",
        "description": "Overrides where the daemon looks for model files. Send `null` to clear the override and fall back to the default location. Backends installed from the registry are unaffected — this is for models supplied out of band.",
        "operationId": "set_custom_models_dir",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomModelsDirBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomModelsDirState"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/language": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read the default transcription language",
        "description": "A BCP-47 tag, `auto`, or `null` when nothing is configured.",
        "operationId": "get_language",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LanguageState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Set the default transcription language",
        "description": "Sets the language every model transcribes in unless something more specific overrides it: a per-model setting, or a `language` field in a single `POST /transcribe` body.",
        "operationId": "set_language",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetLanguageBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LanguageState"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "delete": {
        "tags": [
          "settings"
        ],
        "summary": "Clear the default transcription language",
        "description": "Removes the global setting, returning every model to detecting the language itself. Per-model overrides are untouched.",
        "operationId": "clear_language",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LanguageState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/language/list": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "List the languages the global setting accepts",
        "description": "The tags `POST /settings/language` will take, plus the reserved `auto`.\n\nFill the global language picker from this rather than from a BCP-47 list of your own: the tags are region-qualified on purpose, and a backend is free to declare either `en` or `en-US` for its models — the daemon narrows a qualified global to whichever a model actually serves, which is a rule no client can infer.\n\nA tag for one particular model belongs on that model, at `POST /pipeline/{stage}/model/{model}/language`, whose own list may be narrower.",
        "operationId": "list_languages",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LanguageList"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/notification_method": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read how failures are announced",
        "description": "Answers with the configured method. This governs only failures the user would otherwise never learn about — a transcript that could not be written to the focused window, say — not routine status, which rides on the event stream.",
        "operationId": "get_notification_method",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationMethodState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Choose how failures are announced",
        "description": "Selects how the daemon tells the user when something goes wrong — a desktop notification, or nothing at all. This is about failures the user would otherwise never see, such as a transcript that could not be written to the focused window.",
        "operationId": "set_notification_method",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetNotificationMethodBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationMethodState"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/preview_typing": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read whether live preview typing is on",
        "description": "Answers with the current state. On means a realtime-capable model's partial transcript is typed into the focused window as it forms; off means nothing is written until the transcript is final. A model without a realtime session ignores the setting either way.",
        "operationId": "get_preview_typing",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewTypingState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Turn live preview typing on or off",
        "description": "When on, a realtime-capable model's incremental transcript is typed into the focused window as it forms, and corrected in place as later audio revises it. When off, nothing is written until the transcript is final.",
        "operationId": "set_preview_typing",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreviewTypingBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewTypingState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/recording_stop_mode": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read what currently ends a recording",
        "description": "Answers with the configured mode. It governs daemon-mic captures started through `POST /transcribe`; the pre-captured path has no capture to end, and a `wait: true` caller can always end one by closing the connection.",
        "operationId": "get_recording_stop_mode",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordingStopModeState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Choose what ends a recording",
        "description": "Sets whether a recording stops on an explicit signal, on a period of silence, or on either. This governs daemon-mic captures started through `POST /transcribe`; it has no bearing on the pre-captured path, which has no capture to end.",
        "operationId": "set_recording_stop_mode",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetRecordingStopModeBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordingStopModeState"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/update_beta_optin": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read the update channel opt-in",
        "description": "Answers with the configured opt-in — whether the update check considers beta builds or stable releases only. This is about Super STT itself, not about the backends under `/registry`, which are versioned separately.",
        "operationId": "get_update_beta_optin",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateBetaOptinState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Choose whether updates include prereleases",
        "description": "Selects which release channel the update check considers. Opting in offers beta builds as they are published; opting out considers stable releases only.",
        "operationId": "set_update_beta_optin",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetUpdateBetaOptinBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateBetaOptinState"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/update_check_enabled": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read whether periodic update checks are on",
        "description": "Answers with the current state. Off stops the daemon checking on its own schedule; it does not disable updating, since `POST /update/check` still runs a check on demand.",
        "operationId": "get_update_check_enabled",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateCheckEnabledState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Turn the periodic update check on or off",
        "description": "Controls whether the daemon checks for new Super STT releases on its own schedule. Turning it off does not disable updating — `POST /update/check` still works on demand.",
        "operationId": "set_update_check_enabled",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCheckEnabledBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateCheckEnabledState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/volume": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read the audio cue volume",
        "description": "The level rides in `message` as a bare number — `\"75\"` — not as a field of its own, so parse it back out.",
        "operationId": "get_volume",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Set the audio cue volume",
        "description": "Sets the loudness of the recording cues on a 0–100 scale. `0` silences them without changing which theme is selected; the theme itself is read and written at `/settings/audio_theme`.",
        "operationId": "set_volume",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetVolumeBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/write_method": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read how transcripts are delivered",
        "description": "Answers with the configured preference. What it actually resolves to in this session can differ — `POST /settings/write_method/test` reports both.",
        "operationId": "get_write_method",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteMethodState"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      },
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Choose how transcripts reach the focused window",
        "description": "Selects the mechanism the daemon uses to deliver a finished transcript — simulated typing, the clipboard, and so on. Which mechanisms work depends on the session: some need a compositor that permits synthetic input. Try one with `POST /settings/write_method/test` before committing a user to it.",
        "operationId": "set_write_method",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetWriteMethodBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteMethodState"
                }
              }
            }
          },
          "400": {
            "description": "The value was rejected — out of range, or not one of the accepted tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/settings/write_method/test": {
      "post": {
        "tags": [
          "settings"
        ],
        "summary": "Write sample text using the configured method",
        "description": "Delivers a short sample to the focused window exactly as a real transcript would be, so a user can confirm the method works before relying on it. Focus the window that should receive it first.\n\nThe response reports both the configured preference and what it resolved to, which is how a UI shows that a preferred mechanism silently fell back to another. Refused with `409` while a recording is in flight.",
        "operationId": "test_write_method",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WriteMethodTest"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/status": {
      "get": {
        "tags": [
          "health"
        ],
        "summary": "Current model and device",
        "description": "A snapshot of what the daemon is running: which model is loaded, on which accelerator, and whether a recording cycle is in flight.\n\nSubscriber introspection and other operator detail are not exposed here — see `GET /pipeline/1` and `GET /pipeline/{stage}/model/{model}/device`, which need the `settings` scope.",
        "operationId": "status",
        "responses": {
          "200": {
            "description": "The daemon's current state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DaemonStatus"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `status` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "status"
            ]
          }
        ]
      }
    },
    "/v1/transcribe": {
      "post": {
        "tags": [
          "transcribe"
        ],
        "summary": "Transcribe supplied audio, or start a microphone recording",
        "description": "One endpoint with four behaviours, selected by the body:\n\n| Body | Behaviour | Response |\n|---|---|---|\n| `audio_data` present | Transcribe the supplied buffer; the microphone is never opened | `200` JSON with `transcription` |\n| no `audio_data`, `wait: false` (default) | Start recording and detach; stop it with `POST /transcribe/stop` | `202` with `message: \"Recording started\"` |\n| `wait: true` | Record, then stream the result | `200 text/event-stream`, one `done` frame |\n| `wait: true`, `stream_realtime: true` | As above, plus incremental previews | `200 text/event-stream`, `preview` frames then `done` |\n\nOn the streaming paths a daemon-side failure arrives as a single `error` frame, and closing the connection stops the recording. Frames are:\n\n| `event:` | `data:` |\n|---|---|\n| `preview` | `{ \"text\": \"hello wor…\" }` |\n| `done` | `{ \"transcription\": \"hello world\" }` |\n| `error` | `{ \"message\": \"…\" }` |\n\nStarting while a recording is already in flight is `409 recording_in_progress` — this endpoint only ever *starts* one. Read `busy` from `GET /status` and call `POST /transcribe/stop` to end the running capture.",
        "operationId": "transcribe",
        "requestBody": {
          "description": "All fields optional; the combination selects the behaviour.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TranscribeBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Pre-captured audio: the finished transcription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transcription"
                }
              }
            }
          },
          "202": {
            "description": "Microphone recording started and detached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                },
                "example": {
                  "message": "Recording started",
                  "status": "success"
                }
              }
            }
          },
          "400": {
            "description": "`audio_data` was not an array of numbers, or `stream_realtime` was sent with it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `transcribe` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "A recording is already in flight (`recording_in_progress`), or no model is loaded (`model_not_loaded`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "transcribe"
            ]
          }
        ]
      }
    },
    "/v1/transcribe/realtime": {
      "get": {
        "tags": [
          "transcribe"
        ],
        "summary": "Open a realtime transcription session (WebSocket)",
        "description": "An HTTP/1.1 upgrade to a WebSocket, bridged to the loaded model's realtime session. Send audio frames, receive transcript frames as they form.\n\nOnly realtime-capable models serve this. The daemon caps concurrent sessions and answers `503` rather than queueing beyond it; a session with no incoming frame for a minute is treated as dead and dropped.\n\nBeing a WebSocket, the frame protocol is not describable in OpenAPI — see `docs/protocol/wit/realtime.wit` for the message shapes.",
        "operationId": "realtime_ws_handler",
        "responses": {
          "101": {
            "description": "Upgraded; the realtime session is open."
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `transcribe` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "No model is loaded, or the loaded model has no realtime session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Too many concurrent realtime sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "transcribe"
            ]
          }
        ]
      }
    },
    "/v1/transcribe/stop": {
      "post": {
        "tags": [
          "transcribe"
        ],
        "summary": "Stop the in-flight microphone recording",
        "description": "Ends a recording started by `POST /transcribe`. Idempotent: stopping when nothing is recording succeeds with `No recording in progress`.\n\n`message` says what happened — `Recording stop signal sent`, `Manual stop not enabled in current mode`, or `Transcription in progress, please wait`. The transcript itself does not come back here; it arrives on the `final_stt` event topic, or on the stream if the recording was started with `wait: true`.",
        "operationId": "transcribe_stop",
        "responses": {
          "200": {
            "description": "Stop signal sent, or nothing was recording.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ack"
                },
                "example": {
                  "message": "Recording stop signal sent",
                  "status": "success"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `transcribe` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "transcribe"
            ]
          }
        ]
      }
    },
    "/v1/update": {
      "get": {
        "tags": [
          "update"
        ],
        "summary": "Read the last self-update check",
        "description": "Reports what the most recent check found, without performing one. `checked_at` is `null` until a check has run, and `last_check_error` says why the last attempt failed if it did.\n\nWhich channel is consulted follows `/settings/update_beta_optin`; `beta_optin_effective` reports the setting even before a check has resolved a channel of its own. To force a check now, use `POST /update/check`.",
        "operationId": "get_update",
        "responses": {
          "200": {
            "description": "The last known update state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SelfUpdateStatus"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    },
    "/v1/update/check": {
      "post": {
        "tags": [
          "update"
        ],
        "summary": "Check for a Super STT update now",
        "description": "Runs the check immediately rather than waiting for the daemon's own schedule, and answers with the result — the same shape `GET /update` reports. Works whether or not the periodic check is enabled.\n\nThis only *looks*. Nothing is downloaded or installed as a result.",
        "operationId": "post_check",
        "responses": {
          "200": {
            "description": "The check ran; this is what it found. A network failure is reported in `last_check_error`, not as an HTTP error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SelfUpdateStatus"
                }
              }
            }
          },
          "401": {
            "description": "Token unknown, expired, or its binary changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReasonEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "The token lacks the `settings` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Per-client rate limit hit; back off and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "security": [
          {
            "session_token": [
              "settings"
            ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Ack": {
        "type": "object",
        "description": "The plain acknowledgement: an operation succeeded, with a sentence saying\nwhat happened.\n\nA good number of settings endpoints answer with exactly this, on `GET` as\nwell as `POST` — `GET /volume` reports the level inside `message` rather\nthan as a field of its own. Where that is true the endpoint's own\ndocumentation says so, because a client has to parse the number back out.",
        "required": [
          "status"
        ],
        "properties": {
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable detail. Not a stable identifier — do not switch on it.\n\nOptional because a few commands acknowledge without a sentence, and the\nkey is then absent rather than empty. Every endpoint documented as\ncarrying its value in the message always sets it."
          },
          "status": {
            "type": "string",
            "description": "Always `success`.",
            "example": "success"
          }
        }
      },
      "ActiveBackend": {
        "type": "object",
        "description": "The backend filling stage 1, as that stage's mutations report it.",
        "required": [
          "source",
          "name",
          "model_loaded"
        ],
        "properties": {
          "model_loaded": {
            "type": "boolean",
            "description": "Whether one of its models is currently up."
          },
          "name": {
            "type": "string",
            "description": "Its display name."
          },
          "source": {
            "type": "string",
            "description": "The backend's repo id."
          }
        }
      },
      "AudioTheme": {
        "type": "string",
        "enum": [
          "classic",
          "gentle",
          "minimal",
          "scifi",
          "musical",
          "nature",
          "retro",
          "silent"
        ]
      },
      "AudioThemeList": {
        "type": "object",
        "description": "Every audio cue theme the daemon ships.",
        "required": [
          "status",
          "available_audio_themes"
        ],
        "properties": {
          "available_audio_themes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudioTheme"
            }
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "AudioThemeState": {
        "type": "object",
        "description": "The selected audio cue theme.",
        "required": [
          "status",
          "audio_theme"
        ],
        "properties": {
          "audio_theme": {
            "type": "string",
            "description": "The selected theme's token.",
            "example": "classic"
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "AuthOk": {
        "type": "object",
        "description": "A freshly minted session token.",
        "required": [
          "status",
          "session_token",
          "scopes",
          "expires_at"
        ],
        "properties": {
          "expires_at": {
            "type": "string",
            "description": "RFC 3339 expiry, 30 days out."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The scopes actually granted, sorted and deduplicated."
          },
          "session_token": {
            "type": "string",
            "description": "Send this as `Authorization: Bearer <token>` on every other endpoint.\nBound to the approved binary — it stops working if that binary changes\non disk."
          },
          "status": {
            "type": "string",
            "description": "Always `success`.",
            "example": "success"
          }
        }
      },
      "AuthRequestBody": {
        "type": "object",
        "required": [
          "app_name",
          "scopes"
        ],
        "properties": {
          "app_name": {
            "type": "string",
            "description": "The name shown to the user in the consent popup. Self-reported and\ntherefore untrusted: the daemon identifies you by your binary, and a\nprevious denial sticks to that binary whatever name you send next.",
            "example": "My App"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The scopes to request, at least one. Every entry must be known or the\nwhole request is refused; ask only for what you need, since the user\nsees the list.",
            "example": [
              "transcribe",
              "status"
            ]
          },
          "version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your app's version. Accepted for forwards compatibility; unused today.",
            "example": "0.1"
          }
        }
      },
      "AuthStatusOk": {
        "type": "object",
        "description": "What the token currently held is good for.",
        "required": [
          "status",
          "scopes",
          "expires_at"
        ],
        "properties": {
          "expires_at": {
            "type": "string",
            "description": "RFC 3339 expiry, so a headless client can renew before it lapses."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The scopes the token was minted under."
          },
          "status": {
            "type": "string",
            "description": "Always `success`.",
            "example": "success"
          }
        }
      },
      "BackendCatalog": {
        "type": "object",
        "description": "Every installed backend, with its models, options and secrets.",
        "required": [
          "status",
          "backends"
        ],
        "properties": {
          "backends": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BackendInfo"
            }
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "BackendInfo": {
        "type": "object",
        "description": "A single installed backend and everything the settings UI needs to render\nits section.",
        "required": [
          "source",
          "name",
          "models",
          "secrets",
          "options"
        ],
        "properties": {
          "allowed_hosts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hosts the backend is permitted to reach (`[network].allowed_hosts` from\nits `backend.toml`). Empty for subprocess/local backends. Feeds the\n\"Online model\" badge so the user sees where a cloud backend's audio goes."
          },
          "description": {
            "type": "string",
            "description": "The installed `backend.toml`'s `[backend].description`, empty when the\nmanifest omits it.\n\nA registry entry carries one too, but only for backends the registry\nlists: a sideloaded or imported-from-dir backend has no entry, and its\ndescription would otherwise be invisible everywhere in the UI. `default`\nso a payload written before the field existed still deserializes."
          },
          "installed_accel": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Acceleration backends of the asset variant actually installed on this\nhost, e.g. `[\"cuda\"]` or `[\"cpu\"]`.\n\nEmpty for a backend imported from a local directory, where the binary's\naccel is not knowable, for one installed before the daemon recorded it,\nand for a `wasm` backend — its `installed.json` records `\"wasm\"` for its\nown purposes, but that is a transport, not an accelerator, so it is\nfiltered before it reaches this field. Clients read an empty list as \"no\ninformation\" and fall back to each model's `supported_devices`.\n\nA client offering a device picker intersects: a `cpu` asset offers the\nCPU alone, an accelerated one offers both, since a GPU build still runs\non the CPU."
          },
          "kind": {
            "type": "string",
            "description": "`\"wasm\"` or `\"subprocess\"` — the backend's transport."
          },
          "models": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BackendModel"
            },
            "description": "Models this backend serves."
          },
          "name": {
            "type": "string",
            "description": "Human-readable backend name, e.g. `OpenAI`."
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BackendOption"
            },
            "description": "Non-sensitive options stored in the daemon config."
          },
          "secrets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BackendSecret"
            },
            "description": "Sensitive values (API keys, etc.) stored in the system keyring."
          },
          "source": {
            "type": "string",
            "description": "Repo id the backend was installed from, e.g.\n`github.com/super-stt/openai`. Used as the daemon's keyring account\nkey and option key."
          },
          "version": {
            "type": "string",
            "description": "The installed backend's `[backend].version`, read from the `backend.toml`\non disk — what is installed, not what is published.\n\nFor a backend the registry does not list (imported from a directory, or\ninstalled from an arbitrary repo) this is the only version there is; for\nthe rest it is still the authoritative one, since the registry reports\nwhat a release offers rather than what this machine has. `default` so a\npayload written before the field existed still deserializes."
          }
        }
      },
      "BackendModel": {
        "type": "object",
        "description": "One model served by a backend.",
        "required": [
          "name"
        ],
        "properties": {
          "estimated_vram_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Conservative GPU memory estimate (weights + KV cache + overhead) in\nbytes; `0` when unknown or not GPU-resident. Drives the \"may not fit\"\nwarning when a CUDA load is staged against the detected GPU memory.",
            "minimum": 0
          },
          "multilingual": {
            "type": "boolean",
            "description": "Whether this model supports multiple transcription languages (as\nopposed to a mono-lingual model baked for a single language)."
          },
          "name": {
            "type": "string"
          },
          "primary_language": {
            "type": "string",
            "description": "The model's built-in default language (BCP-47 tag)."
          },
          "realtime": {
            "type": "boolean",
            "description": "Whether the model is driven over the realtime WebSocket path rather than\nbatch `POST /v1/transcribe`."
          },
          "role": {
            "type": "string",
            "description": "What the model is for: `\"transcription\"` (the default) or\n`\"post_processor\"`. A settings UI filters its transcription-model picker\nand its post-processor picker on this.\n\n`default` rather than required, so a catalog from a daemon that predates\nthe field still parses — reading every model as transcribing, which is\nwhat it was."
          },
          "supported_devices": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Devices the model can be loaded onto. Non-empty `snake_case` values\nfrom `[\"cpu\", \"cuda\", \"metal\", \"none\"]`. The settings UI surfaces\nthese as the device choice in the active-backend card; `\"none\"`\n(the only-entry sentinel for online models) means no device picker\nis shown."
          },
          "supported_languages": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "BCP-47 tags the model can transcribe, e.g. `[\"en\", \"es\", \"fr\"]`.\nEmpty for mono-lingual models."
          }
        }
      },
      "BackendOption": {
        "type": "object",
        "description": "A non-sensitive option the backend accepts, stored in the daemon config.",
        "required": [
          "name"
        ],
        "properties": {
          "default": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": "string"
          },
          "label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable label for the UI. Falls back to `name` when absent."
          },
          "name": {
            "type": "string",
            "description": "`snake_case` identifier (the daemon config key; the backend reads it as\n`x-stt-option-<name>`)."
          },
          "required": {
            "type": "boolean"
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "description": "The option's input type (`string` / `integer` / `bool`); absent when the\nbackend declared none."
          },
          "value": {
            "type": [
              "string",
              "null"
            ],
            "description": "Current effective value (override or default) reported by the daemon."
          }
        }
      },
      "BackendOptionValue": {
        "type": "object",
        "description": "One option a backend declares, with the value in effect.",
        "required": [
          "name",
          "label",
          "type",
          "required"
        ],
        "properties": {
          "default": {
            "type": [
              "string",
              "null"
            ],
            "description": "The manifest's default, or `null` when it declares none."
          },
          "label": {
            "type": "string",
            "description": "Human-readable label for a settings UI; falls back to `name`."
          },
          "name": {
            "type": "string",
            "description": "The option's identifier, as the backend's manifest declares it."
          },
          "required": {
            "type": "boolean",
            "description": "Whether the backend refuses to load without a value."
          },
          "type": {
            "type": "string",
            "description": "The declared type — `string`, `number`, and so on."
          },
          "value": {
            "type": [
              "string",
              "null"
            ],
            "description": "What is actually in effect: the user's override if set, otherwise the\ndefault."
          }
        }
      },
      "BackendOptions": {
        "type": "object",
        "description": "Every option a backend declares.",
        "required": [
          "status",
          "options"
        ],
        "properties": {
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BackendOptionValue"
            }
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "BackendSecret": {
        "type": "object",
        "description": "A sensitive value the backend requires, stored in the system keyring.",
        "required": [
          "name"
        ],
        "properties": {
          "description": {
            "type": "string"
          },
          "label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable label for the UI. Falls back to `name` when absent."
          },
          "name": {
            "type": "string",
            "description": "`snake_case` identifier (the keyring account suffix; the backend reads\nit as `x-stt-secret-<name>`)."
          },
          "required": {
            "type": "boolean"
          }
        }
      },
      "Compatibility": {
        "type": "object",
        "required": [
          "compatible"
        ],
        "properties": {
          "compatible": {
            "type": "boolean"
          },
          "needs_client_update": {
            "type": "boolean",
            "description": "Whether the block is \"this Super STT is too old\" rather than \"this\nmachine cannot run it\".\n\nThe two are hidden differently. A host that lacks the right GPU will\nnever run the asset, so Browse tucks it behind \"Show incompatible\"; a\nSuper STT one version behind is a thing the user can fix in a minute,\nand hiding it hides the only notice they would get. `false` on an older\ndaemon that does not send the field, which lists as it always did."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "selected_asset": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SelectedAsset"
              }
            ]
          }
        }
      },
      "CudaHostInfo": {
        "type": "object",
        "description": "The installed NVIDIA driver's CUDA version, e.g. `\"13.3\"`.",
        "required": [
          "driver_version"
        ],
        "properties": {
          "driver_version": {
            "type": "string"
          }
        }
      },
      "CustomModelsDirBody": {
        "type": "object",
        "description": "Point the daemon at a models directory of your own",
        "properties": {
          "path": {
            "type": [
              "string",
              "null"
            ],
            "description": "Absolute path to the directory, or `null` to clear the override."
          }
        }
      },
      "CustomModelsDirState": {
        "type": "object",
        "description": "The models directory override.",
        "required": [
          "status"
        ],
        "properties": {
          "custom_models_dir": {
            "type": [
              "string",
              "null"
            ],
            "description": "The configured directory, or `null` when no override is set. Always\npresent — `null` is the answer, not an absent key."
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "DaemonStatus": {
        "type": "object",
        "description": "What `GET /status` reports.",
        "required": [
          "status",
          "device",
          "model_loaded",
          "busy"
        ],
        "properties": {
          "busy": {
            "type": "boolean",
            "description": "`true` while a daemon-mic cycle is active — capture *and* the\ntranscription and typing that follow it. A toggle hotkey reads this and\ncalls `POST /transcribe/stop` when true, `POST /transcribe` when false."
          },
          "current_model": {
            "type": [
              "string",
              "null"
            ],
            "description": "The loaded model's name. Absent when `model_loaded` is `false`.",
            "example": "whisper-tiny"
          },
          "device": {
            "type": "string",
            "description": "The accelerator the loaded model actually runs on: `cpu`, `cuda`,\n`rocm`, `metal`, `vulkan`, or `remote` for a model served over the\nnetwork. `unknown` when nothing is loaded.",
            "example": "cuda"
          },
          "model_loaded": {
            "type": "boolean",
            "description": "`false` while the initial model is still loading, or after a failed\nswitch."
          },
          "status": {
            "type": "string",
            "description": "Always `success`.",
            "example": "success"
          }
        }
      },
      "DeviceList": {
        "type": "object",
        "description": "The devices a model or a stage can run on.",
        "required": [
          "status",
          "available_devices"
        ],
        "properties": {
          "available_devices": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Accelerator tokens, e.g. `cpu`, `cuda`, `vulkan`.",
            "example": [
              "cpu",
              "cuda"
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "ErrorCode": {
        "type": "string",
        "enum": [
          "recording_in_progress",
          "download_in_progress",
          "no_switch_in_progress",
          "model_not_loaded",
          "invalid_model",
          "invalid_backend",
          "cuda_unavailable",
          "invalid_device",
          "invalid_audio_theme",
          "unsupported_language",
          "invalid_value",
          "not_found",
          "internal",
          "unknown"
        ]
      },
      "ErrorEnvelope": {
        "type": "object",
        "description": "The error envelope, as [`transport.md`] specifies it.\n\n`error_code` is the stable, machine-readable identifier clients switch on\nand the field that determines the HTTP status; `message` is prose for a\nhuman and may be reworded at any time.\n\n[`transport.md`]: https://github.com/jorge-menjivar/super-stt/blob/main/docs/protocol/transport.md",
        "required": [
          "status"
        ],
        "properties": {
          "error_code": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ErrorCode",
                "description": "The stable identifier for this failure. Absent only on an unclassified\nserver-side error."
              }
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable detail."
          },
          "status": {
            "type": "string",
            "description": "Always `error`.",
            "example": "error"
          }
        }
      },
      "GpuHostInfo": {
        "type": "object",
        "description": "Host-wide GPU toolchain/driver versions reported on\n[`GET /gpu_info`](../../../docs/protocol/endpoints/v1/gpu_info.md), independent\nof any one GPU. Each field is `null` when that accelerator's runtime isn't\ndetected on this host — see `docs/protocol/endpoints/v1/gpu_info.md` for\nwhat presence and absence do and don't imply for each one.",
        "properties": {
          "cuda": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/CudaHostInfo"
              }
            ]
          },
          "rocm": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/RocmHostInfo"
              }
            ]
          },
          "vulkan": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/VulkanHostInfo"
              }
            ]
          }
        }
      },
      "GpuInfo": {
        "type": "object",
        "description": "One GPU as reported by [`GET /gpu_info`](../../../docs/protocol/endpoints/v1/gpu_info.md).\n`vendor` is a lowercase `snake_case` tag (`nvidia` / `amd` / `intel` /\n`apple` / `unknown`). `total_bytes` is dedicated VRAM for discrete GPUs and\nthe shared system-memory ceiling for integrated/unified GPUs;\n`free_bytes` / `used_bytes` are `null` when the platform doesn't report them.",
        "required": [
          "name",
          "vendor",
          "total_bytes"
        ],
        "properties": {
          "arch_target": {
            "type": [
              "string",
              "null"
            ],
            "description": "The architecture a prebuilt asset must target to run on this GPU, in\nthe vendor's own spelling: `\"sm_86\"` on NVIDIA, `\"gfx1030\"` on AMD.\n`null` when the driver reports none (an Apple or Intel GPU, or an AMD\ncard on a kernel without KFD)."
          },
          "free_bytes": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "name": {
            "type": "string"
          },
          "total_bytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "used_bytes": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "vendor": {
            "type": "string"
          }
        }
      },
      "GpuInventory": {
        "type": "object",
        "description": "The host's GPUs and its GPU toolchain versions.",
        "required": [
          "status",
          "gpu_info",
          "host"
        ],
        "properties": {
          "gpu_info": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GpuInfo"
            },
            "description": "One entry per detected GPU; empty on a host with none."
          },
          "host": {
            "$ref": "#/components/schemas/GpuHostInfo",
            "description": "Driver and runtime versions, independent of any one GPU."
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "IndexModel": {
        "type": "object",
        "description": "The browse-only model subset the catalog and host-compatibility filter need\nbefore download. The authoritative manifest (languages, files, …) ships as\nthe pinned `manifest` asset and is installed verbatim — it is not re-encoded\nhere. Also the leaf type for `/registry/backends` (`RegistryModel`).",
        "required": [
          "name",
          "supported_devices"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "description": "What the model is for: `\"transcription\"` (the default) or\n`\"post_processor\"`. Lets Browse show that a backend provides a\npost-processor before it is installed. `default` so an index published\nbefore the field existed still parses, reading every model as\ntranscribing — which is what it was."
          },
          "supported_devices": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "IndexOption": {
        "type": "object",
        "required": [
          "name",
          "label",
          "type"
        ],
        "properties": {
          "default": {},
          "label": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        }
      },
      "IndexSecret": {
        "type": "object",
        "required": [
          "name",
          "label",
          "required"
        ],
        "properties": {
          "label": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "required": {
            "type": "boolean"
          }
        }
      },
      "IndexStale": {
        "type": "object",
        "required": [
          "latest_attempted",
          "tag",
          "error",
          "since"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "latest_attempted": {
            "type": "string"
          },
          "since": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          }
        }
      },
      "InstallAccepted": {
        "type": "object",
        "required": [
          "install_id",
          "source",
          "version",
          "selected_asset"
        ],
        "properties": {
          "install_id": {
            "type": "string"
          },
          "selected_asset": {
            "$ref": "#/components/schemas/SelectedAsset"
          },
          "source": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "warning": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "InstallRequest": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "source"
            ],
            "properties": {
              "source": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "repo_url"
            ],
            "properties": {
              "repo_url": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "local_path"
            ],
            "properties": {
              "local_path": {
                "type": "string"
              }
            }
          }
        ]
      },
      "InstallerAsset": {
        "type": "object",
        "required": [
          "name",
          "url",
          "size",
          "sha256"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "sha256": {
            "type": "string",
            "description": "Hex SHA-256 of the binary at `url`, from the release's `SHA256SUMS`\nasset. Always present when `installer_asset` is non-null — clients\nMUST verify the downloaded bytes against this before executing it\n(the daemon omits `installer_asset` entirely rather than publish one\nwithout a verifiable digest)."
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "url": {
            "type": "string"
          }
        }
      },
      "LanguageBody": {
        "type": "object",
        "description": "The language this model should transcribe in.",
        "properties": {
          "language": {
            "type": "string",
            "description": "A BCP-47 tag such as `es`, or `auto` to let the model detect it. Empty is\nrefused — clear an override with `DELETE`.",
            "example": "es"
          }
        }
      },
      "LanguageList": {
        "type": "object",
        "description": "The languages a model can be pinned to.",
        "required": [
          "status",
          "available_languages"
        ],
        "properties": {
          "available_languages": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "BCP-47 tags, plus the reserved `auto`. Empty for a monolingual model,\nwhich has nothing to choose.",
            "example": [
              "auto",
              "en",
              "es"
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "LanguageState": {
        "type": "object",
        "description": "The default transcription language.",
        "required": [
          "status"
        ],
        "properties": {
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "A BCP-47 tag, `auto`, or `null` when nothing is configured. Always\npresent — `null` is the answer, not an absent key.",
            "example": "es"
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "ModelDevice": {
        "type": "object",
        "description": "A model's device preference, what it resolved to, and what this host can\noffer it.",
        "required": [
          "status",
          "available_devices"
        ],
        "properties": {
          "available_devices": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What this host can actually offer this model — the intersection of the\nmachine's accelerators and the builds the model ships. Empty for a model\nthat runs remotely.",
            "example": [
              "cpu",
              "cuda"
            ]
          },
          "device": {
            "type": [
              "string",
              "null"
            ],
            "description": "The preference itself: `cpu`, `gpu`, or a specific accelerator. `none`\nfor a model that runs remotely and therefore has no local device."
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "resolved_accel": {
            "type": [
              "string",
              "null"
            ],
            "description": "What a `gpu` preference resolved to once a model loaded — `cuda`,\n`rocm`, `metal`, `vulkan`. `null` while the preference is `gpu` but\nnothing has loaded yet; equal to the preference when it is `cpu`.\n\nDoubly optional because the wire distinguishes three states and a client\nreads them differently: the key absent means this response does not speak\nto the device at all, an explicit `null` means the preference is `gpu`\nand nothing has resolved it yet, and a value is the accelerator in use.\nCollapsing the first two would report \"unresolved\" where the daemon said\nnothing."
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "ModelLanguageBlock": {
        "type": "object",
        "description": "How one model's transcription language resolves.\n\nThe per-model endpoints answer with this under `language`, where the global\n`/language` endpoints answer with a bare tag. Same field name, different\nshapes: the per-model answer has to explain *why* a language is in effect,\nsince three settings can decide it.",
        "required": [
          "multilingual",
          "source",
          "primary"
        ],
        "properties": {
          "effective": {
            "type": [
              "string",
              "null"
            ],
            "description": "The tag actually used, after resolution. `null` when the model detects\nthe language itself."
          },
          "multilingual": {
            "type": "boolean",
            "description": "Whether this model can transcribe more than one language at all. A\nmonolingual model ignores every setting below."
          },
          "override": {
            "type": [
              "string",
              "null"
            ],
            "description": "The per-model override, or `null` when none is set."
          },
          "primary": {
            "type": "string",
            "description": "The model's own default language."
          },
          "source": {
            "type": "string",
            "description": "Which setting `effective` came from: the per-model override, the global\nsetting, or the model's own default."
          }
        }
      },
      "ModelLanguageState": {
        "type": "object",
        "description": "The per-model language resolution.",
        "required": [
          "status",
          "language"
        ],
        "properties": {
          "language": {
            "$ref": "#/components/schemas/ModelLanguageBlock"
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "ModelList": {
        "type": "object",
        "description": "The models a pipeline stage can run: its backend's, carrying its role.",
        "required": [
          "status",
          "available_models"
        ],
        "properties": {
          "available_models": {
            "type": "array",
            "items": {
              "type": "array",
              "items": false,
              "prefixItems": [
                {
                  "type": "string"
                },
                {
                  "type": "string"
                }
              ]
            },
            "description": "`[name, source]` pairs. Post-processor models are excluded — they are not\nswitchable transcription models, and offering one would fail every\nrecording. The full catalog, roles included, is at `GET /backend/list`.",
            "example": [
              [
                "whisper-tiny",
                "github.com/super-stt/whisper"
              ]
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "NotificationMethodState": {
        "type": "object",
        "description": "How failures are announced.",
        "required": [
          "status",
          "notification_method"
        ],
        "properties": {
          "notification_method": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "OptionBody": {
        "type": "object",
        "description": "The value to store for an option.",
        "properties": {
          "value": {
            "type": "string",
            "description": "The new value. Empty is refused — clear an override with `DELETE`\ninstead, which is the operation that reverts to the manifest default."
          }
        }
      },
      "OptionValue": {
        "type": "object",
        "description": "One option's effective value.",
        "required": [
          "status",
          "name"
        ],
        "properties": {
          "default": {
            "type": [
              "string",
              "null"
            ],
            "description": "The manifest default, so a UI can show what clearing would revert to."
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "example": "success"
          },
          "value": {
            "type": [
              "string",
              "null"
            ],
            "description": "What is in effect now."
          }
        }
      },
      "PipelineReport": {
        "type": "object",
        "description": "The whole pipeline, in order.",
        "required": [
          "status",
          "pipeline"
        ],
        "properties": {
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "pipeline": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StageReport"
            },
            "description": "Stage 1 first. A transcript passes through these in order."
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "PostProcessorState": {
        "type": "object",
        "description": "Stage 2's state, as that stage's mutations report it.",
        "required": [
          "enabled",
          "loaded"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "The user's on/off choice, which is separate from whether the model came\nup: a stage can be enabled with a failed load, and transcripts then pass\nthrough untouched."
          },
          "loaded": {
            "type": "boolean",
            "description": "Whether that model is loaded and ready."
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "The selected model, or `null` when none is picked."
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "description": "The selected backend, or `null` when the stage is empty."
          }
        }
      },
      "PreviewTypingBody": {
        "type": "object",
        "description": "Turn live preview typing on or off",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is on."
          }
        }
      },
      "PreviewTypingState": {
        "type": "object",
        "description": "Whether live preview typing is on.",
        "required": [
          "status",
          "preview_typing_enabled"
        ],
        "properties": {
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "preview_typing_enabled": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "Reason": {
        "type": "object",
        "description": "The `data` object of a [`ReasonEnvelope`].",
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "type": "string",
            "description": "Which case of `message` occurred — e.g. `expired`, `exe_changed`,\n`user_denied`."
          }
        }
      },
      "ReasonEnvelope": {
        "type": "object",
        "description": "The auth-failure envelope: `message` names the failure and `data.reason`\nsays which of its cases occurred.\n\nDistinct from [`ErrorEnvelope`] because the auth surface predates\n`error_code` and clients read `data.reason` there. Both are documented\nrather than reconciled, since changing either is a breaking wire change.",
        "required": [
          "status",
          "message",
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Reason"
          },
          "message": {
            "type": "string",
            "description": "The failure identifier, e.g. `invalid_session` or `auth_denied`."
          },
          "status": {
            "type": "string",
            "description": "Always `error`.",
            "example": "error"
          }
        }
      },
      "RecordingStopModeState": {
        "type": "object",
        "description": "What ends a recording.",
        "required": [
          "status",
          "recording_stop_mode"
        ],
        "properties": {
          "recording_stop_mode": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "RefreshResponse": {
        "type": "object",
        "required": [
          "schema_version",
          "generated_at",
          "backend_count"
        ],
        "properties": {
          "backend_count": {
            "type": "integer",
            "minimum": 0
          },
          "generated_at": {
            "type": "string"
          },
          "schema_version": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          }
        }
      },
      "RegistryBackend": {
        "type": "object",
        "required": [
          "id",
          "source",
          "version",
          "name",
          "license",
          "kind",
          "contract",
          "online",
          "supports_gpu",
          "supports_cpu",
          "models",
          "secrets",
          "options",
          "compatibility"
        ],
        "properties": {
          "allowed_hosts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "backend_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The backend's reverse-DNS identifier, or `None` when the registry entry\npredates it. Names the install directory."
          },
          "compatibility": {
            "$ref": "#/components/schemas/Compatibility"
          },
          "contract": {
            "type": "string",
            "description": "The contract generation the backend declares, as published. Carried\nas a string so a client lists an entry whose generation it does not\nknow; `compatibility` says whether this daemon can drive it."
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string"
          },
          "index_stale": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/IndexStale"
              }
            ]
          },
          "installed_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string"
          },
          "license": {
            "type": "string"
          },
          "min_client": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Super STT release that first understood `contract`, as stamped by\nthe indexer. `None` for an index that predates the stamp."
          },
          "models": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndexModel"
            }
          },
          "name": {
            "type": "string"
          },
          "online": {
            "type": "boolean"
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndexOption"
            }
          },
          "secrets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndexSecret"
            }
          },
          "source": {
            "type": "string"
          },
          "supports_cpu": {
            "type": "boolean"
          },
          "supports_gpu": {
            "type": "boolean"
          },
          "update_available": {
            "type": "boolean",
            "description": "Whether `version` is newer than `installed_version`, decided by the\ndaemon.\n\nThe comparison is semver, and it belongs here rather than in each client\nfor the same reason `installed_version` does: the daemon is what reads\nthe installed manifest and owns the index, so it is the one place that\ncan answer without a client re-deriving it. A client that wants to\npresent the versions still has both.\n\n`false` when nothing is installed, when the installed version is at or\nahead of the index's, or when either version does not parse."
          },
          "version": {
            "type": "string"
          }
        }
      },
      "RegistryError": {
        "type": "object",
        "description": "The registry surface's error envelope, which carries one extra key.\n\nThese endpoints shipped before `error_code` existed, spelling the failure\nidentity as `error`. That key is still sent, because clients read it; the\nstandard `error_code` was added alongside rather than in place of it, so the\nwhole surface honors the \"`error_code` on every error\" rule without breaking\nanyone. Both name the same failure and always agree.\n\nDocumented as its own shape rather than folded into [`ErrorEnvelope`]:\n`error` appears *only* here, and putting it on the shared envelope would\ntell every other endpoint's reader to expect a key they will never receive.",
        "required": [
          "status",
          "error_code",
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "The same identifier under the key this surface has always used. Retained\nfor clients written against it; prefer `error_code`.",
            "example": "not_found"
          },
          "error_code": {
            "type": "string",
            "description": "The stable identifier for this failure.",
            "example": "not_found"
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable detail, when there is any to add."
          },
          "status": {
            "type": "string",
            "description": "Always `error`.",
            "example": "error"
          }
        }
      },
      "RegistryListResponse": {
        "type": "object",
        "required": [
          "schema_version",
          "generated_at",
          "backends"
        ],
        "properties": {
          "backends": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RegistryBackend"
            }
          },
          "generated_at": {
            "type": "string"
          },
          "schema_version": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          }
        }
      },
      "RocmHostInfo": {
        "type": "object",
        "description": "The installed `ROCm` userspace release, e.g. `\"6.2.4\"`. Advisory only — see\n`docs/protocol/endpoints/v1/gpu_info.md`; `arch_target` is what a build must\nactually match.",
        "required": [
          "version"
        ],
        "properties": {
          "version": {
            "type": "string"
          }
        }
      },
      "SecretBody": {
        "type": "object",
        "description": "The secret to store.",
        "properties": {
          "value": {
            "type": "string",
            "description": "The credential itself. Written to the system keyring, never returned by\nany endpoint. Empty is refused — clear a secret with `DELETE`."
          }
        }
      },
      "SecretConfigured": {
        "type": "object",
        "description": "Whether one secret is set.",
        "required": [
          "status",
          "configured"
        ],
        "properties": {
          "configured": {
            "type": "boolean",
            "description": "Whether a value is stored."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Absent on write and clear, which answer about the secret just addressed."
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "SecretList": {
        "type": "object",
        "description": "Every secret a backend declares.",
        "required": [
          "status",
          "secrets"
        ],
        "properties": {
          "secrets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SecretState"
            }
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "SecretState": {
        "type": "object",
        "description": "One secret a backend declares, and whether it is set.",
        "required": [
          "name",
          "label",
          "required",
          "configured"
        ],
        "properties": {
          "configured": {
            "type": "boolean",
            "description": "Whether a value is stored. The value itself is never returned."
          },
          "label": {
            "type": "string",
            "description": "Human-readable label for a settings UI; falls back to `name`."
          },
          "name": {
            "type": "string",
            "description": "The secret's identifier, as the backend's manifest declares it."
          },
          "required": {
            "type": "boolean",
            "description": "Whether the backend refuses to load without it."
          }
        }
      },
      "SelectedAsset": {
        "type": "object",
        "required": [
          "target",
          "accel"
        ],
        "properties": {
          "accel": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Acceleration backends the selected build carries. A single entry is\nboth read and written as a bare string, a list of two or more as an\narray — a client that declares this field as a plain `String` still\nparses the catalog for every asset that carries one runtime."
          },
          "cuda_major": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "minimum": 0
          },
          "cuda_sm": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "minimum": 0
          },
          "cudnn": {
            "type": "boolean"
          },
          "target": {
            "type": "string"
          }
        }
      },
      "SelfUpdateStatus": {
        "type": "object",
        "required": [
          "current_version",
          "update_available",
          "beta_optin_effective"
        ],
        "properties": {
          "beta_optin_effective": {
            "type": "boolean"
          },
          "checked_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "current_version": {
            "type": "string"
          },
          "installer_asset": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/InstallerAsset"
              }
            ]
          },
          "last_check_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "latest_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "update_available": {
            "type": "boolean"
          }
        }
      },
      "SetAudioThemeBody": {
        "type": "object",
        "description": "Select the audio cue theme",
        "required": [
          "theme"
        ],
        "properties": {
          "theme": {
            "type": "string",
            "description": "A theme token from `GET /settings/audio_theme/list`, e.g. `classic`. An unknown token is a `400`."
          }
        }
      },
      "SetBackendBody": {
        "type": "object",
        "description": "Which backend should fill the stage.",
        "required": [
          "source"
        ],
        "properties": {
          "source": {
            "type": "string",
            "description": "The backend's repo id, as `GET /backend/list` reports it.",
            "example": "github.com/acme/whisper"
          }
        }
      },
      "SetDeviceBody": {
        "type": "object",
        "description": "Which accelerator the model should run on.",
        "required": [
          "device"
        ],
        "properties": {
          "device": {
            "type": "string",
            "description": "An accelerator token from the stage's or model's device list — `cpu`,\n`cuda`, `vulkan`, or the generic `gpu`.",
            "example": "cuda"
          }
        }
      },
      "SetLanguageBody": {
        "type": "object",
        "description": "Set the default transcription language",
        "required": [
          "language"
        ],
        "properties": {
          "language": {
            "type": "string",
            "description": "A BCP-47 tag such as `es`, or `auto` to let the model detect the language."
          }
        }
      },
      "SetModelBody": {
        "type": "object",
        "description": "Which model to run in the stage.",
        "required": [
          "model"
        ],
        "properties": {
          "model": {
            "type": "string",
            "description": "The model's name.",
            "example": "whisper-tiny"
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "description": "The backend serving it. Omitted resolves to the backend already selected\nfor this stage."
          }
        }
      },
      "SetNotificationMethodBody": {
        "type": "object",
        "description": "Choose how failures are announced",
        "required": [
          "method"
        ],
        "properties": {
          "method": {
            "type": "string",
            "description": "One of the accepted `snake_case` method tokens. An unknown token is a `400`."
          }
        }
      },
      "SetRecordingStopModeBody": {
        "type": "object",
        "description": "Choose what ends a recording",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "description": "One of the accepted `snake_case` mode tokens. An unknown token is a `400`."
          }
        }
      },
      "SetUpdateBetaOptinBody": {
        "type": "object",
        "description": "Choose whether updates include prereleases",
        "required": [
          "value"
        ],
        "properties": {
          "value": {
            "type": "string",
            "description": "One of the accepted `snake_case` opt-in tokens. An unknown token is a `400`."
          }
        }
      },
      "SetVolumeBody": {
        "type": "object",
        "description": "Set the audio cue volume",
        "required": [
          "volume"
        ],
        "properties": {
          "volume": {
            "type": "integer",
            "format": "int32",
            "description": "Integer in `0..=100`. Anything outside that range is a `400`.",
            "minimum": 0
          }
        }
      },
      "SetWriteMethodBody": {
        "type": "object",
        "description": "Choose how transcripts reach the focused window",
        "required": [
          "method"
        ],
        "properties": {
          "method": {
            "type": "string",
            "description": "One of the accepted `snake_case` method tokens. An unknown token is a `400`."
          }
        }
      },
      "StageEnvelope": {
        "type": "object",
        "description": "One stage of the pipeline.",
        "required": [
          "status",
          "stage"
        ],
        "properties": {
          "stage": {
            "$ref": "#/components/schemas/StageReport"
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "StageModelDevice": {
        "type": "object",
        "description": "Which accelerator a stage's model runs on.",
        "required": [
          "preference"
        ],
        "properties": {
          "preference": {
            "type": "string",
            "description": "The stored preference: `cpu`, `gpu`, or `none` for a model that runs\nremotely and therefore has no local device."
          },
          "resolved_accel": {
            "type": [
              "string",
              "null"
            ],
            "description": "What a `gpu` preference resolved to once the model loaded — `cuda`,\n`rocm`, `metal`, `vulkan`. `null` while the preference is `gpu` and\nnothing has confirmed it yet, so a client is never told a device\nresolved before a load proved it."
          }
        }
      },
      "StageModelEnvelope": {
        "type": "object",
        "description": "One stage's model slot.",
        "required": [
          "status",
          "model"
        ],
        "properties": {
          "model": {
            "$ref": "#/components/schemas/StageModelReport"
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "StageModelReport": {
        "type": "object",
        "description": "The model slot of one stage: what is selected, whether it is up, the device\nit runs on, and the load still in flight.\n\nAnswers `GET /pipeline/{stage}/model`, and answers it the same way at every\nposition — which is the point of it being its own object. `model` is the\n*selection* and survives an unload; `loaded` says whether that selection is\nrunning right now.",
        "required": [
          "stage",
          "loaded"
        ],
        "properties": {
          "device": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/StageModelDevice",
                "description": "The accelerator the selection runs on; `null` when nothing is selected.\n\nWhat it *could* run on is `GET /pipeline/{stage}/model/{model}/device/list`,\nkept out of here deliberately: that list costs a host probe, and a card\nfills its picker from it once rather than on every poll of this."
              }
            ]
          },
          "loaded": {
            "type": "boolean",
            "description": "Whether that model is loaded and ready to run."
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "The model selected in this stage; `null` when none is picked."
          },
          "stage": {
            "type": "integer",
            "format": "int32",
            "description": "The stage whose model slot this is.",
            "minimum": 0
          },
          "switch": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/StageSwitch",
                "description": "The load or download in flight for this stage; `null` when idle.\n\nHere rather than on the stage because it names a model. The daemon runs\none model operation at a time but not always for the same stage, so it\nis reported per stage."
              }
            ]
          }
        }
      },
      "StageMutation": {
        "type": "object",
        "description": "The answer to a stage mutation.\n\nThe two stages answer with different keys — stage 1 with `active_backend`,\nstage 2 with `post_processor` — because each grew its own endpoint before\nthe pipeline addressed stages by position. Both are documented rather than\nreconciled: changing either is a breaking wire change. Read the stage back\nwith `GET /pipeline/{stage}` for the one shape both share.",
        "required": [
          "status"
        ],
        "properties": {
          "active_backend": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ActiveBackend",
                "description": "Stage 1 only. `null` when the stage was emptied.\n\nDoubly optional for the same reason `resolved_accel` is: absent means\nthis was a stage 2 mutation, which reports `post_processor` instead;\n`null` means stage 1 itself is now empty."
              }
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "post_processor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PostProcessorState",
                "description": "Stage 2 only."
              }
            ]
          },
          "status": {
            "type": "string",
            "example": "success"
          }
        }
      },
      "StageReport": {
        "type": "object",
        "description": "One stage of the pipeline: which backend fills it, and whether the user has\nit switched on.\n\nA stage reports its *backend*, not its model. The model is one level down,\nat `GET /pipeline/{stage}/model`, as [`StageModelReport`].\n\nThe two were one object until the stages were made to behave alike, and the\nsplit is what fixed them: stage 1 reported the model it had *loaded* while\nstage 2 reported the model it had *selected*, so the same field meant\ndifferent things at the two positions — and at stage 1 `loaded` was true\nexactly when `model` was non-null, carrying no information at all.\n\n`source` and `name` serialize as an explicit `null` rather than being\nomitted: a stage reports its whole shape whatever state it is in, so a\nclient can read `source` to decide whether the stage is filled without\nfirst checking the key exists.",
        "required": [
          "stage",
          "role",
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the user has this stage switched on — what Load sets and Unload\nclears.\n\nSeparate from whether the model actually came up, which is `loaded` on\n[`StageModelReport`]: a stage can be enabled while its load failed, and\ntranscripts then pass through untouched. Every stage carries one. Stage\n1 did not until the stages were made to behave alike, which is why its\nunload had to throw the selection away to stay idle across a restart."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "That backend's display name; `null` when the stage is empty."
          },
          "role": {
            "$ref": "#/components/schemas/StageRole"
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "description": "The backend filling this stage; `null` when the stage is empty."
          },
          "stage": {
            "type": "integer",
            "format": "int32",
            "description": "Position in the pipeline: [`TRANSCRIPTION_STAGE`], [`POST_PROCESSOR_STAGE`].",
            "minimum": 0
          }
        }
      },
      "StageRole": {
        "type": "string",
        "description": "What a stage does to the transcript passing through it.",
        "enum": [
          "transcription",
          "post_processor"
        ]
      },
      "StageSwitch": {
        "type": "object",
        "description": "A model load in flight for one stage.",
        "required": [
          "phase",
          "target",
          "started_at",
          "download"
        ],
        "properties": {
          "download": {
            "$ref": "#/components/schemas/SwitchDownload",
            "description": "Byte and file progress, for the `downloading` phase."
          },
          "phase": {
            "type": "string",
            "description": "Where the operation has got to: `downloading`, `loading_model`,\n`cancelled`, `completed`, or `error`."
          },
          "started_at": {
            "type": "string",
            "description": "RFC 3339 timestamp of when the operation started."
          },
          "target": {
            "$ref": "#/components/schemas/SwitchTarget",
            "description": "The model being loaded into the stage."
          }
        }
      },
      "SwitchDownload": {
        "type": "object",
        "description": "Download progress within a [`StageSwitch`].",
        "required": [
          "current_file",
          "file_index",
          "total_files",
          "bytes_downloaded",
          "total_bytes",
          "percentage"
        ],
        "properties": {
          "bytes_downloaded": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "current_file": {
            "type": "string"
          },
          "eta_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Estimated seconds remaining, or `null` before there is enough history\nto estimate one.",
            "minimum": 0
          },
          "file_index": {
            "type": "integer",
            "minimum": 0
          },
          "percentage": {
            "type": "number",
            "format": "float",
            "description": "0.0–100.0 across the whole operation."
          },
          "total_bytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "total_files": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "SwitchTarget": {
        "type": "object",
        "description": "The model a [`StageSwitch`] is loading.",
        "required": [
          "model",
          "source"
        ],
        "properties": {
          "model": {
            "type": "string"
          },
          "source": {
            "type": "string"
          }
        }
      },
      "TranscribeBody": {
        "type": "object",
        "description": "Pre-captured one-shot: transcribe a supplied `audio_data` buffer without\ntouching the microphone and return a single JSON `{ transcription }` (or a\ncoded error). Rejects `stream_realtime` combined with `audio_data` per the\ncontract.\nThe body of `POST /transcribe`. Every field is optional; which combination\nyou send selects one of the four behaviours the endpoint documents.\n\nDeclared, not deserialized. The handler reads the body as raw JSON so it can\n*move* a large `audio_data` buffer out of it rather than copying it into a\nsecond owned `Vec`; this type is what that body's shape is, published in the\n`OpenAPI` document and kept beside the handler that parses it.",
        "properties": {
          "audio_data": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "number",
              "format": "float"
            },
            "description": "Mono PCM samples in `-1.0..=1.0`. Present means \"transcribe this buffer\"\n— the daemon does not touch the microphone, and answers with one JSON\nresult rather than a stream."
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "BCP-47 tag, or `auto`, overriding the configured language for this\nrequest only.",
            "example": "es"
          },
          "sample_rate": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Sample rate of `audio_data`, in Hz. Ignored on the microphone paths.",
            "example": 16000,
            "minimum": 0
          },
          "stream_realtime": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Microphone paths only, and only with `wait: true`: also emit incremental\n`preview` frames as the transcript forms. Rejected with `400` alongside\n`audio_data`, which has nothing to stream."
          },
          "wait": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Microphone paths only. `false` (the default) starts the recording and\nreturns immediately; `true` holds the connection open and streams the\nresult."
          }
        }
      },
      "Transcription": {
        "type": "object",
        "description": "A one-shot transcription result, for the pre-captured path.",
        "required": [
          "status",
          "transcription"
        ],
        "properties": {
          "status": {
            "type": "string",
            "description": "Always `success`.",
            "example": "success"
          },
          "transcription": {
            "type": "string",
            "description": "The recognized text. Empty when the audio held no speech — which is a\nsuccessful transcription, not a failure.",
            "example": "hello world"
          }
        }
      },
      "UninstallResponse": {
        "type": "object",
        "required": [
          "uninstalled",
          "was_active"
        ],
        "properties": {
          "uninstalled": {
            "type": "boolean"
          },
          "was_active": {
            "type": "boolean",
            "description": "The backend was filling stage 1, which was emptied before the files\nwent."
          },
          "was_post_processor": {
            "type": "boolean",
            "description": "The backend was filling stage 2 — selected as the post-processor\nbackend, loaded or not — which was emptied before the files went.\nAbsent from an older daemon's answer, which reads as `false`."
          }
        }
      },
      "UpdateBetaOptinState": {
        "type": "object",
        "description": "Which release channel updates come from.",
        "required": [
          "status",
          "update_beta_optin"
        ],
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "update_beta_optin": {
            "type": "string"
          }
        }
      },
      "UpdateCheckEnabledBody": {
        "type": "object",
        "description": "Turn the periodic update check on or off",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is on."
          }
        }
      },
      "UpdateCheckEnabledState": {
        "type": "object",
        "description": "Whether the periodic update check runs.",
        "required": [
          "status",
          "update_check_enabled"
        ],
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "update_check_enabled": {
            "type": "boolean"
          }
        }
      },
      "UpdateRequest": {
        "type": "object",
        "required": [
          "source"
        ],
        "properties": {
          "source": {
            "type": "string"
          }
        }
      },
      "UpdateResponse": {
        "type": "object",
        "required": [
          "from_version",
          "to_version",
          "noop"
        ],
        "properties": {
          "from_version": {
            "type": "string"
          },
          "install_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "noop": {
            "type": "boolean"
          },
          "to_version": {
            "type": "string"
          }
        }
      },
      "VulkanHostInfo": {
        "type": "object",
        "description": "The highest Vulkan API version any installed driver advertises, e.g.\n`\"1.3.280\"`.",
        "required": [
          "api_version"
        ],
        "properties": {
          "api_version": {
            "type": "string"
          }
        }
      },
      "WriteMethodState": {
        "type": "object",
        "description": "How transcripts reach the focused window.",
        "required": [
          "status",
          "write_method"
        ],
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "write_method": {
            "type": "string"
          }
        }
      },
      "WriteMethodTest": {
        "type": "object",
        "description": "The outcome of writing sample text with the configured method.",
        "required": [
          "status"
        ],
        "properties": {
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "resolved_write_method": {
            "type": [
              "string",
              "null"
            ],
            "description": "What that preference resolved to for this session, which can differ when\nthe compositor will not permit the preferred mechanism."
          },
          "status": {
            "type": "string",
            "example": "success"
          },
          "write_method": {
            "type": [
              "string",
              "null"
            ],
            "description": "The configured preference."
          }
        }
      }
    },
    "securitySchemes": {
      "session_token": {
        "type": "http",
        "scheme": "bearer",
        "description": "Session token from `POST /v1/auth/request`. Bound to the calling binary and valid for 30 days."
      }
    }
  },
  "tags": [
    {
      "name": "auth",
      "description": "Consent handshake and token probing."
    },
    {
      "name": "health",
      "description": "Liveness and what the daemon is currently running."
    },
    {
      "name": "transcribe",
      "description": "Start, stop and stream transcription."
    },
    {
      "name": "events",
      "description": "Server-Sent Events for recording state, audio levels, model and download progress, and final transcripts."
    },
    {
      "name": "pipeline",
      "description": "The ordered stages a transcript passes through: which backend fills each, which model runs there, and on what device."
    },
    {
      "name": "settings",
      "description": "Stored daemon preferences, one value apiece, all under `/v1/settings`: audio cues, write and notification methods, language, update policy. Sharing the `settings` scope is not the same as being a setting — `backends`, `pipeline` and `registry` are guarded by it too."
    },
    {
      "name": "hardware",
      "description": "What the daemon can see of this machine: GPUs, drivers, runtimes."
    },
    {
      "name": "update",
      "description": "Whether a newer daemon exists, and asking it to look now."
    },
    {
      "name": "backends",
      "description": "Installed backends: their models, options and secrets."
    },
    {
      "name": "registry",
      "description": "The published backend catalog: browse, install, update, uninstall."
    }
  ]
}
