{
  "openapi": "3.1.0",
  "info": {
    "title": "Sunny Patneedi public site and API",
    "version": "1.0.0",
    "summary": "Read-only HTTP interface to sunnypatneedi.com: public pages as HTML or Markdown, discovery files and the API.",
    "description": "Everything described here is public and read-only. No authentication is needed.\n\n- Pages: every public page is available as HTML or, with format=markdown or Accept: text/markdown, as Markdown. The page values match https://sunnypatneedi.com/sitemap.xml.\n- API: paths under /api return JSON: Sunny Patneedi's projects and public profile, built from the same content as the pages, and a health check. They are rate limited per client IP address and send RateLimit-Policy and RateLimit header fields (draft-ietf-httpapi-ratelimit-headers-11).\n- Errors: API errors, and the site's 400, 404 and 405 errors for clients that prefer JSON, are RFC 9457 problem details (application/problem+json) with a stable code field.\n\nGuide for developers and AI agents: https://sunnypatneedi.com/developers. Guidance for AI assistants: https://sunnypatneedi.com/llms.txt.",
    "contact": {
      "name": "Sunny Patneedi",
      "url": "https://sunnypatneedi.com/contact"
    }
  },
  "servers": [
    {
      "url": "https://sunnypatneedi.com",
      "description": "Production"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Developers and AI agents guide",
    "url": "https://sunnypatneedi.com/developers"
  },
  "tags": [
    {
      "name": "pages",
      "description": "Public pages, as HTML or Markdown."
    },
    {
      "name": "discovery",
      "description": "Machine-readable files that describe the site."
    },
    {
      "name": "health",
      "description": "Health operations"
    },
    {
      "name": "projects",
      "description": "Sunny Patneedi's projects, with the status and last-checked date that https://sunnypatneedi.com/projects shows for each."
    },
    {
      "name": "profile",
      "description": "Sunny Patneedi's public profile, as published on the site."
    }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getHomePage",
        "tags": [
          "pages"
        ],
        "summary": "Get the homepage",
        "description": "Returns Sunny Patneedi's homepage, an overview of his work and the role he is looking for. HTML by default; Markdown with format=markdown or Accept: text/markdown.",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Set to \"markdown\" to get the page as Markdown (text/markdown), the same as sending Accept: text/markdown. Omit it to get HTML.",
            "schema": {
              "type": "string",
              "enum": [
                "markdown"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Page"
          },
          "default": {
            "$ref": "#/components/responses/SiteError"
          }
        }
      }
    },
    "/{page}": {
      "get": {
        "operationId": "getPage",
        "tags": [
          "pages"
        ],
        "summary": "Get a public page",
        "description": "Returns one public page of sunnypatneedi.com, such as about, contact or developers. HTML by default; Markdown with format=markdown or Accept: text/markdown. The allowed values are the site's sitemap entries.",
        "parameters": [
          {
            "name": "page",
            "in": "path",
            "required": true,
            "description": "Name of the page. Values:\n\n- about: About Sunny Patneedi | Build with AI. Understand what you build.\n- learn: Learn with Sunny Patneedi | Build with AI. Understand what you build.\n- high-agency-learning: What Is High-Agency Learning?\n- frameworks: Frameworks\n- writing: Writing | Written thoughts on building with AI\n- work: Work\n- speaking: Sunny Patneedi | Speaking on AI and the Future of Learning\n- press: Sunny Patneedi | Bio, Headshots and Media\n- contact: Contact\n- developers: Developers and AI agents\n- work-with-me: Work with me\n- projects: Projects\n- terms: Terms of Service\n- privacy: Privacy Policy",
            "schema": {
              "type": "string",
              "enum": [
                "about",
                "learn",
                "high-agency-learning",
                "frameworks",
                "writing",
                "work",
                "speaking",
                "press",
                "contact",
                "developers",
                "work-with-me",
                "projects",
                "terms",
                "privacy"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Set to \"markdown\" to get the page as Markdown (text/markdown), the same as sending Accept: text/markdown. Omit it to get HTML.",
            "schema": {
              "type": "string",
              "enum": [
                "markdown"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Page"
          },
          "404": {
            "$ref": "#/components/responses/PageNotFound"
          },
          "default": {
            "$ref": "#/components/responses/SiteError"
          }
        }
      }
    },
    "/frameworks/{guide}": {
      "get": {
        "operationId": "getFrameworkGuide",
        "tags": [
          "pages"
        ],
        "summary": "Get a framework guide",
        "description": "Returns one of Sunny Patneedi's framework guides. HTML by default; Markdown with format=markdown or Accept: text/markdown. The list of all frameworks is the frameworks page.",
        "parameters": [
          {
            "name": "guide",
            "in": "path",
            "required": true,
            "description": "Name of the guide. Values:\n\n- scaffold-or-surrender: Scaffold or Surrender?\n- build-to-become: Build to Become",
            "schema": {
              "type": "string",
              "enum": [
                "scaffold-or-surrender",
                "build-to-become"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Set to \"markdown\" to get the page as Markdown (text/markdown), the same as sending Accept: text/markdown. Omit it to get HTML.",
            "schema": {
              "type": "string",
              "enum": [
                "markdown"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Page"
          },
          "404": {
            "$ref": "#/components/responses/PageNotFound"
          },
          "default": {
            "$ref": "#/components/responses/SiteError"
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "tags": [
          "discovery"
        ],
        "summary": "Get guidance for AI assistants",
        "description": "Returns llms.txt: when to use this site, the authoritative public pages to cite, and guidance for describing Sunny Patneedi's work accurately. Read it before summarizing or citing the site.",
        "responses": {
          "200": {
            "description": "The llms.txt guide.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "Markdown-formatted plain text."
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/SiteError"
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "tags": [
          "discovery"
        ],
        "summary": "Get the sitemap",
        "description": "Returns the XML sitemap: every public page, each with its last-modified date.",
        "responses": {
          "200": {
            "description": "The sitemap.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string",
                  "description": "A sitemaps.org urlset."
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/SiteError"
          }
        }
      }
    },
    "/.well-known/api-catalog": {
      "get": {
        "operationId": "getApiCatalog",
        "tags": [
          "discovery"
        ],
        "summary": "Get the API catalog",
        "description": "Returns the RFC 9727 API catalog (media type application/linkset+json with profile \"https://www.rfc-editor.org/info/rfc9727\"). It links to this OpenAPI description, the developer documentation, the API health check and the API's projects and profile endpoints.",
        "responses": {
          "200": {
            "description": "The API catalog.",
            "headers": {
              "Link": {
                "description": "Identifies the catalog: </.well-known/api-catalog>; rel=\"api-catalog\".",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/linkset+json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCatalog"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/SiteError"
          }
        }
      }
    },
    "/api/healthz": {
      "get": {
        "operationId": "healthCheck",
        "tags": [
          "health"
        ],
        "summary": "Health check",
        "description": "Reports whether the API server is running. Returns {\"status\": \"ok\"} while the server is up. Use it to confirm the API is reachable before relying on it.",
        "responses": {
          "200": {
            "description": "Healthy",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthStatus"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/projects": {
      "get": {
        "operationId": "listProjects",
        "tags": [
          "projects"
        ],
        "summary": "List projects",
        "description": "Returns every project in the archive at https://sunnypatneedi.com/projects, in the page's default order: current work first, then earlier experiments. Each project has its status, what that status means, its last-checked date and its verified link, exactly as the page shows them. Quote statuses and dates as given: a project without a check date is unverified, and a \"source\" link is a public repository, not a released product. There are no usage or customer figures.",
        "responses": {
          "200": {
            "description": "Every project.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectList"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/projects/{projectId}": {
      "get": {
        "operationId": "getProject",
        "tags": [
          "projects"
        ],
        "summary": "Get a project",
        "description": "Returns one project from https://sunnypatneedi.com/projects, with the same fields as listProjects. Use it to check a single project's status or last-checked date. listProjects returns every id.",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The project's id from listProjects, such as \"puddle\" or \"spear\": lowercase letters, digits and hyphens.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
              "examples": [
                "puddle"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The project.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/ProjectNotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/profile": {
      "get": {
        "operationId": "getProfile",
        "tags": [
          "profile"
        ],
        "summary": "Get Sunny Patneedi's public profile",
        "description": "Returns Sunny Patneedi's public profile as the site publishes it: name and title, the approved bios from https://sunnypatneedi.com/press, his career as listed on the homepage, his current advisory role, the role he is looking for, his verified profile links and how to get in touch. It contains no email addresses; the contact page and LinkedIn are the ways to reach him.",
        "responses": {
          "200": {
            "description": "The public profile.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Profile"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "HealthStatus": {
        "type": "object",
        "description": "Health of the API server.",
        "properties": {
          "status": {
            "type": "string",
            "description": "Always \"ok\" while the server is running."
          }
        },
        "required": [
          "status"
        ]
      },
      "ProjectList": {
        "type": "object",
        "description": "Every project in the archive at https://sunnypatneedi.com/projects.",
        "properties": {
          "page": {
            "type": "string",
            "format": "uri",
            "description": "The page that publishes these projects. Cite it when quoting them."
          },
          "projects": {
            "type": "array",
            "description": "Current work first, then earlier experiments, in the page's default order.",
            "items": {
              "$ref": "#/components/schemas/Project"
            }
          }
        },
        "required": [
          "page",
          "projects"
        ]
      },
      "Project": {
        "type": "object",
        "description": "One project, as the archive at https://sunnypatneedi.com/projects describes it.",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
            "description": "Stable id, for getProject."
          },
          "name": {
            "type": "string",
            "description": "The project's name."
          },
          "purpose": {
            "type": "string",
            "description": "What the project is for."
          },
          "audience": {
            "type": "string",
            "description": "Who the project is for."
          },
          "status": {
            "type": "string",
            "enum": [
              "Available",
              "Private preview",
              "Experiment",
              "Planned"
            ],
            "description": "The published status. statusMeaning says what it means; the projects page shows the same legend."
          },
          "statusMeaning": {
            "type": "string",
            "description": "What the status means, from the status legend on the projects page."
          },
          "stage": {
            "type": "string",
            "enum": [
              "Current work",
              "Earlier experiment"
            ],
            "description": "Whether the project is current work or an earlier experiment."
          },
          "type": {
            "type": "string",
            "enum": [
              "Web App",
              "Mobile",
              "Open Source"
            ],
            "description": "The kind of project."
          },
          "category": {
            "type": "string",
            "description": "The topic the projects page filters by, such as Learning or Family."
          },
          "verification": {
            "$ref": "#/components/schemas/ProjectVerification"
          },
          "evidenceSource": {
            "type": "string",
            "description": "What the last check looked at."
          },
          "link": {
            "description": "The verified public destination, or null when none was verified.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ProjectLink"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "purpose",
          "audience",
          "status",
          "statusMeaning",
          "stage",
          "type",
          "category",
          "verification",
          "evidenceSource",
          "link"
        ]
      },
      "ProjectVerification": {
        "type": "object",
        "description": "The last check of the project's public destination or flow.",
        "properties": {
          "checkedOn": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Date of the last check (YYYY-MM-DD), or null when the project has no dated check and is unverified."
          },
          "label": {
            "type": "string",
            "description": "The check as the site words it, such as \"Checked 9 October 2026\" or \"Not checked yet\"."
          },
          "scope": {
            "type": "string",
            "description": "What the check covered and what it did not."
          }
        },
        "required": [
          "checkedOn",
          "label",
          "scope"
        ]
      },
      "ProjectLink": {
        "type": "object",
        "description": "A verified public destination.",
        "properties": {
          "label": {
            "type": "string",
            "description": "The link text on the projects page."
          },
          "href": {
            "type": "string",
            "format": "uri",
            "description": "The destination URL."
          },
          "kind": {
            "type": "string",
            "enum": [
              "site",
              "source"
            ],
            "description": "\"site\": a public page that was reached. \"source\": a public repository, which shows the source code only, not a released product."
          }
        },
        "required": [
          "label",
          "href",
          "kind"
        ]
      },
      "Profile": {
        "type": "object",
        "description": "Sunny Patneedi's public profile, as published on the site. It contains no email addresses.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Full name."
          },
          "title": {
            "type": "string",
            "description": "Current title."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The canonical personal site."
          },
          "image": {
            "type": "string",
            "format": "uri",
            "description": "Headshot photo."
          },
          "bios": {
            "type": "object",
            "description": "The approved bios from https://sunnypatneedi.com/press. Use them verbatim.",
            "properties": {
              "words25": {
                "type": "string",
                "description": "The 25-word bio."
              },
              "words60": {
                "type": "string",
                "description": "The 60-word bio."
              },
              "words150": {
                "type": "string",
                "description": "The 150-word bio. A blank line separates its paragraphs."
              }
            },
            "required": [
              "words25",
              "words60",
              "words150"
            ]
          },
          "career": {
            "type": "array",
            "description": "Career history as listed on the homepage, most recent first.",
            "items": {
              "$ref": "#/components/schemas/CareerRole"
            }
          },
          "advisory": {
            "type": "object",
            "description": "Current advisory role.",
            "properties": {
              "role": {
                "type": "string",
                "description": "The role and organization."
              },
              "description": {
                "type": "string",
                "description": "What the advisory work is."
              }
            },
            "required": [
              "role",
              "description"
            ]
          },
          "lookingFor": {
            "type": "object",
            "description": "The role Sunny is looking for, as the homepage and About page state it.",
            "properties": {
              "summary": {
                "type": "string",
                "description": "The role in one sentence."
              },
              "endToEnd": {
                "type": "array",
                "description": "What owning the product end to end covers.",
                "items": {
                  "type": "string"
                }
              },
              "mandate": {
                "type": "array",
                "description": "What the role needs to include.",
                "items": {
                  "type": "string"
                }
              },
              "evidence": {
                "type": "string",
                "description": "The evidence Sunny gives for it."
              }
            },
            "required": [
              "summary",
              "endToEnd",
              "mandate",
              "evidence"
            ]
          },
          "profiles": {
            "type": "array",
            "description": "Verified profiles on other sites, as the press page lists them.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "The site, such as LinkedIn or GitHub."
                },
                "url": {
                  "type": "string",
                  "format": "uri",
                  "description": "The profile URL."
                }
              },
              "required": [
                "name",
                "url"
              ]
            }
          },
          "contact": {
            "type": "object",
            "description": "How to get in touch.",
            "properties": {
              "page": {
                "type": "string",
                "format": "uri",
                "description": "The contact page, which lists the topics Sunny takes conversations on."
              },
              "linkedin": {
                "type": "string",
                "format": "uri",
                "description": "LinkedIn, where the contact page sends messages."
              }
            },
            "required": [
              "page",
              "linkedin"
            ]
          }
        },
        "required": [
          "name",
          "title",
          "url",
          "image",
          "bios",
          "career",
          "advisory",
          "lookingFor",
          "profiles",
          "contact"
        ]
      },
      "CareerRole": {
        "type": "object",
        "description": "One role in Sunny's career.",
        "properties": {
          "organization": {
            "type": "string",
            "description": "Where the role was."
          },
          "role": {
            "type": "string",
            "description": "The role."
          },
          "years": {
            "type": "string",
            "description": "The years as published, such as \"2018 — 2025\" or \"2025 — now\"."
          },
          "outcome": {
            "type": [
              "string",
              "null"
            ],
            "description": "One known outcome of the role, or null when the site lists none."
          }
        },
        "required": [
          "organization",
          "role",
          "years",
          "outcome"
        ]
      },
      "ProblemDetails": {
        "type": "object",
        "description": "An RFC 9457 problem details object (media type application/problem+json). The API returns it for every error, and the website returns it for 400, 404 and 405 errors when the request prefers JSON. \"code\" is stable and safe to branch on; \"title\", \"detail\" and \"hint\" are for people and may change.",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "Identifies the problem type. Most types link to their entry in the error reference at https://sunnypatneedi.com/developers#errors; rate limiting uses the quota-exceeded type from draft-ietf-httpapi-ratelimit-headers-11."
          },
          "title": {
            "type": "string",
            "description": "Short summary of the problem type."
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599,
            "description": "The HTTP status code of this response."
          },
          "detail": {
            "type": "string",
            "description": "Explanation of this occurrence of the problem."
          },
          "instance": {
            "type": "string",
            "format": "uri-reference",
            "description": "The request path that produced the problem."
          },
          "code": {
            "type": "string",
            "description": "Stable, machine-readable error code.",
            "enum": [
              "bad_request",
              "malformed_body",
              "invalid_path",
              "payload_too_large",
              "unsupported_media_type",
              "not_found",
              "method_not_allowed",
              "rate_limited",
              "internal_error"
            ]
          },
          "hint": {
            "type": "string",
            "description": "What to do next, with a link to the relevant documentation."
          },
          "violated-policies": {
            "type": "array",
            "description": "Names of the rate-limit policies the client exceeded. Present only on rate_limited errors.",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "code",
          "hint"
        ]
      },
      "ApiCatalog": {
        "type": "object",
        "description": "An RFC 9727 API catalog in the RFC 9264 linkset format. Each entry's anchor is an API; its link relations point to that API's description (service-desc), documentation (service-doc), health check (status) and data endpoints (item).",
        "required": [
          "linkset"
        ],
        "properties": {
          "linkset": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "anchor"
              ],
              "properties": {
                "anchor": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "additionalProperties": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "href"
                  ],
                  "properties": {
                    "href": {
                      "type": "string",
                      "format": "uri"
                    },
                    "type": {
                      "type": "string",
                      "description": "Media type of the link target."
                    },
                    "title": {
                      "type": "string",
                      "description": "What the link target is."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "headers": {
      "RateLimitPolicy": {
        "description": "The quota policy, as defined in draft-ietf-httpapi-ratelimit-headers-11: \"default\";q=120;w=60 means 120 requests per 60-second window for each client IP address. Counts are kept separately by each server instance.",
        "schema": {
          "type": "string",
          "examples": [
            "\"default\";q=120;w=60"
          ]
        }
      },
      "RateLimit": {
        "description": "The quota remaining under the policy (r) and the seconds until the current window resets (t), as defined in draft-ietf-httpapi-ratelimit-headers-11.",
        "schema": {
          "type": "string",
          "examples": [
            "\"default\";r=119;t=60"
          ]
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "responses": {
      "TooManyRequests": {
        "description": "The client exceeded the rate limit. Wait for the number of seconds in Retry-After before retrying.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "ProjectNotFound": {
        "description": "No project has this id. listProjects returns every project's id.",
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "InternalError": {
        "description": "The server failed unexpectedly. Retry later.",
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "Page": {
        "description": "The page, as HTML by default or as Markdown when requested.",
        "headers": {
          "Link": {
            "description": "The page's Markdown version (rel=\"alternate\"; type=\"text/markdown\") and the API catalog (rel=\"api-catalog\").",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "text/html": {
            "schema": {
              "type": "string",
              "description": "The prerendered page, including one JSON-LD structured data graph."
            }
          },
          "text/markdown": {
            "schema": {
              "type": "string",
              "description": "The page's text, headings and links as Markdown."
            }
          }
        }
      },
      "PageNotFound": {
        "description": "No public page has this name. Clients that prefer JSON (Accept: application/json) get problem details; others get an HTML or Markdown page that links to the sitemap and llms.txt.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          },
          "text/html": {
            "schema": {
              "type": "string",
              "description": "An HTML error page."
            }
          },
          "text/markdown": {
            "schema": {
              "type": "string",
              "description": "A Markdown error page."
            }
          }
        }
      },
      "SiteError": {
        "description": "An error. For 400 (invalid path), 404 (not found) and 405 (method not allowed; this site is read-only), clients that prefer JSON get problem details with a stable code.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          },
          "text/html": {
            "schema": {
              "type": "string",
              "description": "An HTML error page."
            }
          },
          "text/markdown": {
            "schema": {
              "type": "string",
              "description": "A Markdown error page."
            }
          },
          "text/plain": {
            "schema": {
              "type": "string",
              "description": "A plain-text error message."
            }
          }
        }
      }
    }
  }
}
