{
  "openapi": "3.1.0",
  "info": {
    "title": "Salus Cloud public discovery API",
    "version": "2026-08-25",
    "summary": "The unauthenticated, machine-readable surface of salus.cloud: discovery documents, the MCP server descriptor and tool catalogue, and the public CLI distribution endpoints.",
    "description": "Salus Cloud's programmatic interface for agents is **MCP**, not REST. This document describes the public, unauthenticated endpoints an agent can fetch without credentials in order to discover Salus and connect to it: the discovery documents on `salus.cloud`, the MCP server descriptor and tool catalogue, the CLI and Claude Desktop extension downloads on `download.salus.cloud`, and the OpenID Connect discovery document on `auth.salus.cloud`.\n\nTo *read* everything the site says in one fetch rather than crawling it, get `/llms-full.txt` — the full prose of all 49 pages, each chapter stamped with its source URL. `/llms.txt` is the short index.\n\nTo *operate* the platform — create projects, deploy repositories, provision databases, read logs and metrics, roll back releases — connect the Salus MCP server described at `/mcp.json` and listed in `/mcp-tools.json` (52 tools). Every tool acts as the signed-in Salus user with that user's own access.\n\nThe authenticated platform REST API behind the product is versioned and used by the Salus CLI and console, but it is **not publicly specified**: it carries no compatibility commitment and is not documented here. Use MCP or the CLI. If you need a supported REST contract, contact us at https://salus.cloud/talk-to-sales/.\n\n## Versioning and change policy\n\nThese discovery documents are **unversioned and additive**: paths are stable, and new fields may appear without notice. Nothing here is removed or renamed without first carrying `Deprecation` and `Sunset` response headers (RFC 9745 / RFC 8594) for at least 90 days. `info.version` above is the document date, not a URL-path version — there is deliberately no `/v1/` prefix on a static discovery surface, because the alternative is a redirect layer that buys nothing. Every same-origin response echoes that date as the `Salus-Discovery-Version` header, so a cached client can detect a change without refetching and diffing.\n\nThis policy is also machine-readable: `info.x-versioning`, `info.x-deprecation` and `info.x-rate-limits` carry it as fields, and the `Deprecation`, `Sunset` and `Link` headers are declared on every same-origin `200` below. `info.x-deprecation.deprecatedPaths` is empty — nothing here is deprecated today.\n\nThe authenticated platform API is separate, versioned in its URL path, and **not covered by this policy or this document** — it carries no public compatibility commitment. Use MCP or the CLI.\n\n## Rate limits\n\nNone at the origin. Every path here is a static file, unmetered and safe to poll; there are no `RateLimit` headers to read because nothing is being counted. DDoS protection at the CDN may still refuse abusive volumes. Be reasonable and cache — `/mcp-tools.json` changes on CLI releases, not per request. Compare `Salus-Discovery-Version` to detect a change cheaply. See `info.x-rate-limits`.\n\n## Errors\n\nA request for a path that does not exist returns **404** with a body negotiated from `Accept`: an RFC 9457 `application/problem+json` document (carrying a machine-readable `code` and recovery URLs), markdown, or HTML. See the `404` response on any operation below.",
    "contact": {
      "name": "Salus Cloud",
      "url": "https://salus.cloud/developers/",
      "email": "hello@salus.cloud"
    },
    "license": {
      "name": "Documentation © Salus Cloud Corporation",
      "url": "https://salus.cloud/privacy-policy/"
    },
    "x-versioning": {
      "scheme": "date",
      "current": "2026-08-25",
      "stability": "additive-only",
      "urlPathVersioned": false,
      "versionRequestHeader": null,
      "versionResponseHeader": "Salus-Discovery-Version",
      "policyUrl": "https://salus.cloud/developers/#versioning",
      "summary": "These discovery documents are unversioned in the URL and additive in content: paths are stable and new fields may appear without notice. The version is the document date, echoed on every same-origin response as the Salus-Discovery-Version header, so a client can tell one snapshot from another without diffing the document. There is deliberately no /v1/ prefix: on a static discovery surface it buys a redirect layer and nothing else. The authenticated platform API is separate, versioned in its own URL path, and not covered by this document or this policy."
    },
    "x-deprecation": {
      "mechanism": "response-headers",
      "headers": [
        "Deprecation",
        "Sunset",
        "Link"
      ],
      "specifications": [
        "https://www.rfc-editor.org/rfc/rfc9745",
        "https://www.rfc-editor.org/rfc/rfc8594",
        "https://www.rfc-editor.org/rfc/rfc8288"
      ],
      "minimumNoticeDays": 90,
      "deprecatedPaths": [],
      "policyUrl": "https://salus.cloud/developers/#versioning",
      "summary": "Nothing in this document is removed or renamed without first carrying a Deprecation header (RFC 9745) and a Sunset header (RFC 8594) for at least 90 days, with a Link rel=\"successor-version\" pointing at the replacement where one exists. Those headers are declared on every same-origin operation below and are absent while a path is current. deprecatedPaths is empty: nothing on this surface is deprecated today."
    },
    "x-rate-limits": {
      "enforced": false,
      "headers": [],
      "policyUrl": "https://salus.cloud/developers/#rate-limits",
      "summary": "No rate limiting at the origin. Every path in this document is a static file, unmetered, and safe to poll. No RateLimit or RateLimit-Policy headers are emitted because nothing is being counted — publishing them for a limit nobody enforces would hand a client a number to self-throttle against that corresponds to no real budget. DDoS protection at the CDN may still refuse abusive volumes; those thresholds are not published and are not expressed as RateLimit headers.",
      "guidance": "Cache rather than poll aggressively: /mcp-tools.json changes on CLI releases and the discovery documents change on site deploys, not per request. Compare the Salus-Discovery-Version response header to detect a change cheaply."
    }
  },
  "externalDocs": {
    "description": "Salus developer and agent resources",
    "url": "https://salus.cloud/developers/"
  },
  "servers": [
    {
      "url": "https://salus.cloud",
      "description": "Marketing site and discovery documents"
    }
  ],
  "tags": [
    {
      "name": "discovery",
      "description": "Machine-readable documents describing the site, the product, and how to recover from a bad path."
    },
    {
      "name": "mcp",
      "description": "Descriptors for the Salus MCP server — the supported programmatic interface."
    },
    {
      "name": "distribution",
      "description": "Public downloads for the Salus CLI and the Claude Desktop extension."
    },
    {
      "name": "authorization",
      "description": "OpenID Connect discovery for the Salus identity provider."
    }
  ],
  "paths": {
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "tags": [
          "discovery"
        ],
        "summary": "Product summary for language models",
        "description": "An llms.txt document: what Salus is, what it does for agents, pricing, and an index of every marketing page and documentation page.",
        "externalDocs": {
          "description": "llms.txt specification",
          "url": "https://llmstxt.org/"
        },
        "responses": {
          "200": {
            "description": "The llms.txt document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "operationId": "getLlmsFullTxt",
        "tags": [
          "discovery"
        ],
        "summary": "Complete site content in one file",
        "description": "Every page on salus.cloud as markdown, in reading order, concatenated into a single document. Each chapter is stamped with the URL it came from and is byte-identical to what that URL serves under `Accept: text/markdown`. Generated at build time from the same source as the per-page twins, so the two cannot disagree. Fetch this instead of crawling 49 URLs when you want the whole site; fetch /llms.txt when you want the index and the orientation.",
        "externalDocs": {
          "description": "llms.txt specification",
          "url": "https://llmstxt.org/"
        },
        "responses": {
          "200": {
            "description": "The concatenated site content, roughly 150 KB of markdown.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/robots.txt": {
      "get": {
        "operationId": "getRobotsTxt",
        "tags": [
          "discovery"
        ],
        "summary": "Crawl policy",
        "description": "Robots Exclusion Protocol rules. Salus allows AI and agent crawlers; named agent user-agents are listed explicitly.",
        "externalDocs": {
          "description": "RFC 9309 — Robots Exclusion Protocol",
          "url": "https://www.rfc-editor.org/rfc/rfc9309.html"
        },
        "responses": {
          "200": {
            "description": "The robots.txt document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap-index.xml": {
      "get": {
        "operationId": "getSitemapIndex",
        "tags": [
          "discovery"
        ],
        "summary": "Sitemap index",
        "description": "Sitemap index pointing at the URL sitemaps for every indexable page on salus.cloud.",
        "externalDocs": {
          "description": "Sitemaps XML format",
          "url": "https://www.sitemaps.org/protocol.html"
        },
        "responses": {
          "200": {
            "description": "A `<sitemapindex>` document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/XmlDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/404.md": {
      "get": {
        "operationId": "getNotFoundGuide",
        "tags": [
          "discovery"
        ],
        "summary": "Recovery guide for missing pages",
        "description": "A short markdown document listing where to look next when a path does not exist. This is also the response body served — with HTTP status 404 — for any unknown path when the request's `Accept` header prefers `text/markdown` or `text/plain`.",
        "responses": {
          "200": {
            "description": "The recovery guide.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiJson",
        "tags": [
          "discovery"
        ],
        "summary": "This document, as JSON",
        "responses": {
          "200": {
            "description": "An OpenAPI 3.1 document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenApiDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        },
        "description": "This document. The machine-readable index of the public Salus Cloud surface: which discovery documents exist, where the CLI and MCP bundle live, and how authentication works. Fetch this first if you are deciding whether and how to integrate."
      }
    },
    "/openapi.yaml": {
      "get": {
        "operationId": "getOpenApiYaml",
        "tags": [
          "discovery"
        ],
        "summary": "This document, as YAML",
        "description": "Byte-for-byte equivalent to `/openapi.json`, serialised as YAML.",
        "responses": {
          "200": {
            "description": "An OpenAPI 3.1 document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/yaml": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/mcp.json": {
      "get": {
        "operationId": "getMcpServerDescriptor",
        "tags": [
          "mcp"
        ],
        "summary": "MCP server descriptor",
        "description": "An MCP registry `server.json` descriptor for the Salus MCP server, including how to obtain and run it.",
        "externalDocs": {
          "description": "Model Context Protocol",
          "url": "https://modelcontextprotocol.io"
        },
        "responses": {
          "200": {
            "description": "An MCP `server.json` document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpServerDescriptor"
                },
                "example": {
                  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
                  "name": "cloud.salus/salus",
                  "version": "1.0.0",
                  "websiteUrl": "https://salus.cloud/developers/"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-tools.json": {
      "get": {
        "operationId": "getMcpToolCatalogue",
        "tags": [
          "mcp"
        ],
        "summary": "MCP tool catalogue",
        "description": "The tools the Salus MCP server exposes, each with its capability tier (`read`, `write`, `operate`, `destructive`), plus the authorization model and the tool-exposure presets. Published for discovery; a live MCP `tools/list` call is authoritative for full input schemas.",
        "responses": {
          "200": {
            "description": "A tool catalogue conforming to `/mcp-tools.schema.json`.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpToolCatalogue"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-tools.schema.json": {
      "get": {
        "operationId": "getMcpToolCatalogueSchema",
        "tags": [
          "mcp"
        ],
        "summary": "JSON Schema for the MCP tool catalogue",
        "responses": {
          "200": {
            "description": "A JSON Schema 2020-12 document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonSchemaDocument"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        },
        "description": "JSON Schema 2020-12 for /mcp-tools.json. Validate the catalogue against this before relying on its shape, and use it to generate types."
      }
    },
    "/install.sh": {
      "get": {
        "operationId": "getCliInstaller",
        "tags": [
          "distribution"
        ],
        "servers": [
          {
            "url": "https://download.salus.cloud",
            "description": "Public CLI and extension distribution"
          }
        ],
        "summary": "Salus CLI installer script",
        "description": "POSIX shell installer. Detects OS and CPU architecture, downloads the matching `salus` binary and installs it to /usr/local/bin (override with SALUS_INSTALL_DIR). Intended to be piped to bash:\n\n    curl -fsSL https://download.salus.cloud/install.sh | bash",
        "responses": {
          "200": {
            "description": "The installer script.",
            "content": {
              "text/x-shellscript": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/salus-cli-{os}-{arch}": {
      "get": {
        "operationId": "getCliBinary",
        "tags": [
          "distribution"
        ],
        "servers": [
          {
            "url": "https://download.salus.cloud",
            "description": "Public CLI and extension distribution"
          }
        ],
        "summary": "Salus CLI binary",
        "description": "The `salus` binary for one platform. Always the current release — these URLs are unversioned. `install.sh` resolves the right one for you; fetch directly only if you are packaging Salus yourself.",
        "parameters": [
          {
            "name": "os",
            "in": "path",
            "required": true,
            "description": "Operating system.",
            "schema": {
              "type": "string",
              "enum": [
                "darwin",
                "linux"
              ]
            }
          },
          {
            "name": "arch",
            "in": "path",
            "required": true,
            "description": "CPU architecture.",
            "schema": {
              "type": "string",
              "enum": [
                "arm64",
                "x64"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "An executable binary.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "$ref": "#/components/schemas/BinaryFile"
                }
              }
            }
          },
          "404": {
            "description": "No build for that OS/architecture combination."
          }
        }
      }
    },
    "/salus-mcp.mcpb": {
      "get": {
        "operationId": "getMcpBundle",
        "tags": [
          "distribution"
        ],
        "servers": [
          {
            "url": "https://download.salus.cloud",
            "description": "Public CLI and extension distribution"
          }
        ],
        "summary": "Claude Desktop extension bundle",
        "description": "The Salus MCP server packaged as an MCP bundle (.mcpb) for one-click installation into Claude Desktop — no terminal required. This is the artifact referenced by the `mcpb` package entry in /mcp.json.",
        "responses": {
          "200": {
            "description": "An MCP bundle (zip archive).",
            "content": {
              "application/zip": {
                "schema": {
                  "$ref": "#/components/schemas/BinaryFile"
                }
              }
            }
          }
        }
      }
    },
    "/realms/salus/.well-known/openid-configuration": {
      "get": {
        "operationId": "getOpenIdConfiguration",
        "tags": [
          "authorization"
        ],
        "servers": [
          {
            "url": "https://auth.salus.cloud",
            "description": "Salus identity provider (OpenID Connect)"
          }
        ],
        "summary": "OpenID Connect discovery document",
        "description": "Authorization, token and JWKS endpoints for the Salus identity provider, plus supported grant types and PKCE code-challenge methods. The CLI and MCP server use the authorization code flow with PKCE (S256).",
        "externalDocs": {
          "description": "OpenID Connect Discovery 1.0",
          "url": "https://openid.net/specs/openid-connect-discovery-1_0.html"
        },
        "responses": {
          "200": {
            "description": "An OpenID Provider metadata document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenIdProviderMetadata"
                }
              }
            }
          }
        }
      }
    },
    "/404.json": {
      "get": {
        "operationId": "getNotFoundProblem",
        "tags": [
          "discovery"
        ],
        "summary": "Recovery guide for missing paths, as RFC 9457",
        "description": "The JSON form of the 404 recovery document: a machine-readable `code`, a human-readable `detail`, and a `recovery` map of where to look next. This same body is returned — with status 404 — for any unknown path when the request prefers `application/json` or `application/problem+json`. Fetched on its own URL it answers 200, so it can be inspected without provoking an error.",
        "responses": {
          "200": {
            "description": "The problem document.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/ai-catalog.json": {
      "get": {
        "operationId": "getAiCatalog",
        "tags": [
          "discovery"
        ],
        "summary": "Agentic Resource Discovery capability manifest",
        "description": "ARD manifest listing the machine-readable resources Salus Cloud publishes, each with a description and the representative queries it answers. Advertised three ways so an agent only has to know one: this well-known URI, the `Agentmap:` directive in robots.txt, and `<link rel=\"ai-catalog\">` on every page. Served with `Access-Control-Allow-Origin: *` so browser-hosted agents can read it.",
        "responses": {
          "200": {
            "description": "An ARD manifest.",
            "headers": {
              "Salus-Discovery-Version": {
                "$ref": "#/components/headers/SalusDiscoveryVersion"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              },
              "Link": {
                "$ref": "#/components/headers/DeprecationLink"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "specVersion",
                    "host",
                    "entries"
                  ],
                  "properties": {
                    "specVersion": {
                      "type": "string"
                    },
                    "host": {
                      "type": "object"
                    },
                    "entries": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "404": {
            "description": "No resource at that path. The body is negotiated from `Accept`: an RFC 9457 problem document for JSON clients, markdown for agents, HTML otherwise. The status is 404 in every case.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "about:blank",
                  "title": "Not Found",
                  "status": 404,
                  "code": "not_found",
                  "detail": "That path does not exist on salus.cloud."
                }
              },
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/TextDocument"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "salusOidc": {
        "type": "openIdConnect",
        "openIdConnectUrl": "https://auth.salus.cloud/realms/salus/.well-known/openid-configuration",
        "description": "OpenID Connect against the Salus identity provider. The Salus CLI and MCP server use the authorization code flow with PKCE (S256) and short-lived refreshable tokens; the token is stored locally and shared between the CLI binary and the MCP server. No endpoint in this document requires it — it is declared so agents can discover how authenticated access works.\n\n⚠️ The scopes below are the realm's standard OIDC scopes, verified against its discovery document. Salus does NOT currently define API-level scopes (there is no read:projects / write:deployments). Authorization is enforced by platform RBAC after the token is issued — org-, space- and project-scoped roles — not by OAuth scope. An agent cannot today request least-privilege access via scope; it inherits the access of the person who signed in. Tool-level narrowing is available client-side instead, via the MCP server's tool presets (see /mcp-tools.json)."
      },
      "salusOAuth2": {
        "type": "oauth2",
        "description": "The same identity provider expressed as an OAuth 2.0 flow, so the available scopes are machine-readable. These are the realm's ACTUAL scopes_supported — standard OIDC only. There are no Salus-specific resource scopes to request.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://auth.salus.cloud/realms/salus/protocol/openid-connect/auth",
            "tokenUrl": "https://auth.salus.cloud/realms/salus/protocol/openid-connect/token",
            "refreshUrl": "https://auth.salus.cloud/realms/salus/protocol/openid-connect/token",
            "scopes": {
              "openid": "Issue an ID token identifying the signed-in user. Required.",
              "profile": "Basic profile claims (name, preferred username).",
              "email": "Email address and verification status.",
              "offline_access": "Issue a refresh token so the CLI and MCP server can renew without re-prompting.",
              "roles": "Include the user's realm and client role claims in the token.",
              "acr": "Authentication context class reference.",
              "address": "Postal address claim.",
              "phone": "Phone number claim.",
              "web-origins": "Keycloak-managed CORS origins for the client.",
              "microprofile-jwt": "MicroProfile JWT claims (upn, groups)."
            }
          }
        }
      }
    },
    "headers": {
      "SalusDiscoveryVersion": {
        "description": "The version of the discovery surface that produced this response — the same value as `info.version` in /openapi.json, and the stamp carried by /llms-full.txt. Date-based and additive; compare it to detect a change without refetching and diffing the documents themselves.",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date",
          "example": "2026-08-25"
        }
      },
      "Deprecation": {
        "description": "RFC 9745. Present only once this path has been deprecated; its value is the date the deprecation took effect. Absent while the path is current — presence is the signal, so treat any value as \"stop integrating against this\". Always accompanied by `Sunset`.",
        "required": false,
        "schema": {
          "type": "string",
          "example": "@1793491200"
        }
      },
      "Sunset": {
        "description": "RFC 8594. The earliest date this path may stop responding, as an HTTP-date. Emitted alongside `Deprecation` and never less than 90 days ahead of it. Absent while the path is current.",
        "required": false,
        "schema": {
          "type": "string",
          "example": "Wed, 01 Apr 2026 00:00:00 GMT"
        }
      },
      "DeprecationLink": {
        "description": "RFC 8288 Link header. On a deprecated path it carries `rel=\"successor-version\"` pointing at the replacement, and `rel=\"deprecation\"` pointing at the policy. On a current path it carries the site's ordinary service-doc, service-desc, describedby and ai-catalog links instead.",
        "required": false,
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem detail. Returned for a 404 when the request prefers JSON.",
        "required": [
          "type",
          "title",
          "status"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri-reference",
            "description": "Problem type URI. `about:blank` when the status code carries all the semantics, per RFC 9457 §4.2 — used here deliberately rather than a bespoke URI that would itself 404.",
            "examples": [
              "about:blank"
            ]
          },
          "title": {
            "type": "string",
            "description": "Short, human-readable summary.",
            "examples": [
              "Not Found"
            ]
          },
          "status": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599,
            "description": "HTTP status code, duplicated in the body.",
            "examples": [
              404
            ]
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code. Safe to branch on.",
            "examples": [
              "not_found"
            ]
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation specific to this occurrence."
          },
          "instance": {
            "type": "string",
            "format": "uri-reference",
            "description": "URI of the specific occurrence. Absent on this static surface."
          },
          "recovery": {
            "type": "object",
            "description": "Salus extension: where to look next. Keys are stable; values are absolute URLs.",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          },
          "contact": {
            "type": "string",
            "description": "Salus extension: a human to ask.",
            "examples": [
              "hello@salus.cloud"
            ]
          }
        },
        "additionalProperties": true
      },
      "McpServerDescriptor": {
        "type": "object",
        "description": "MCP registry server.json descriptor.",
        "required": [
          "name",
          "version",
          "description"
        ],
        "properties": {
          "$schema": {
            "type": "string",
            "format": "uri"
          },
          "name": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$",
            "description": "Reverse-DNS server name.",
            "examples": [
              "cloud.salus/salus"
            ]
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string",
            "examples": [
              "1.0.0"
            ]
          },
          "websiteUrl": {
            "type": "string",
            "format": "uri"
          },
          "packages": {
            "type": "array",
            "description": "How to obtain and run the server.",
            "items": {
              "type": "object",
              "required": [
                "registryType",
                "identifier",
                "transport"
              ],
              "properties": {
                "registryType": {
                  "type": "string",
                  "description": "Distribution channel.",
                  "examples": [
                    "mcpb"
                  ]
                },
                "identifier": {
                  "type": "string",
                  "description": "Package id, or a URL for registryType mcpb."
                },
                "version": {
                  "type": "string"
                },
                "transport": {
                  "type": "object",
                  "required": [
                    "type"
                  ],
                  "properties": {
                    "type": {
                      "type": "string",
                      "enum": [
                        "stdio",
                        "streamable-http",
                        "sse"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      },
      "McpTool": {
        "type": "object",
        "required": [
          "name",
          "tier",
          "description"
        ],
        "properties": {
          "name": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$",
            "description": "Tool name as passed to MCP tools/call.",
            "examples": [
              "deploy_repo"
            ]
          },
          "title": {
            "type": "string",
            "description": "Human-readable label for permission prompts."
          },
          "tier": {
            "type": "string",
            "enum": [
              "read",
              "write",
              "operate",
              "destructive"
            ],
            "description": "Capability tier, ordered by escalating risk."
          },
          "description": {
            "type": "string"
          }
        }
      },
      "McpToolCatalogue": {
        "type": "object",
        "description": "The tools the Salus MCP server exposes. Discovery only — a live MCP tools/list call is authoritative for full input schemas.",
        "required": [
          "server",
          "descriptor",
          "generated",
          "toolCount",
          "tools"
        ],
        "properties": {
          "$schema": {
            "type": "string",
            "format": "uri"
          },
          "server": {
            "type": "string",
            "description": "Matches the name field of the descriptor at /mcp.json."
          },
          "descriptor": {
            "type": "string",
            "format": "uri"
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          },
          "generated": {
            "type": "string",
            "format": "date"
          },
          "provenance": {
            "type": "string"
          },
          "transport": {
            "type": "string",
            "enum": [
              "stdio",
              "http",
              "sse"
            ]
          },
          "authorization": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string"
              },
              "flow": {
                "type": "string"
              },
              "issuer": {
                "type": "string",
                "format": "uri"
              },
              "discovery": {
                "type": "string",
                "format": "uri"
              },
              "notes": {
                "type": "string"
              }
            }
          },
          "tiers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "presets": {
            "type": "object",
            "description": "Named tool-exposure presets. Each value is the tier list it enables, or prose.",
            "additionalProperties": true
          },
          "defaultPreset": {
            "type": "string"
          },
          "presetNote": {
            "type": "string"
          },
          "toolCount": {
            "type": "integer",
            "minimum": 0,
            "description": "Equals tools.length."
          },
          "tools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/McpTool"
            }
          },
          "enterpriseOnlyTools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/McpTool"
            }
          }
        }
      },
      "OpenApiDocument": {
        "type": "object",
        "description": "An OpenAPI 3.1 document.",
        "required": [
          "openapi",
          "info",
          "paths"
        ],
        "properties": {
          "openapi": {
            "type": "string",
            "pattern": "^3\\.",
            "examples": [
              "3.1.0"
            ]
          },
          "info": {
            "type": "object",
            "required": [
              "title",
              "version"
            ],
            "properties": {
              "title": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "paths": {
            "type": "object",
            "additionalProperties": true
          },
          "components": {
            "type": "object",
            "additionalProperties": true
          },
          "servers": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        },
        "additionalProperties": true
      },
      "JsonSchemaDocument": {
        "type": "object",
        "description": "A JSON Schema 2020-12 document.",
        "properties": {
          "$schema": {
            "type": "string",
            "format": "uri"
          },
          "$id": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "properties": {
            "type": "object",
            "additionalProperties": true
          },
          "required": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "$defs": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "OpenIdProviderMetadata": {
        "type": "object",
        "description": "OpenID Provider metadata (OpenID Connect Discovery 1.0 / RFC 8414).",
        "required": [
          "issuer",
          "authorization_endpoint",
          "token_endpoint",
          "jwks_uri"
        ],
        "properties": {
          "issuer": {
            "type": "string",
            "format": "uri"
          },
          "authorization_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "token_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "jwks_uri": {
            "type": "string",
            "format": "uri"
          },
          "registration_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "revocation_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "grant_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "code_challenge_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      },
      "TextDocument": {
        "type": "string",
        "description": "A plain-text or markdown document."
      },
      "XmlDocument": {
        "type": "string",
        "description": "An XML document."
      },
      "BinaryFile": {
        "type": "string",
        "format": "binary"
      }
    }
  }
}
