{
  "openapi": "3.1.0",
  "info": {
    "title": "Che-Yu Wu Public Archive",
    "version": "1.0.0",
    "description": "Read-only access to published artist records. Search snippets are excerpts. Read every page until nextOffset is null with a consistent revision, or download markdownUrl for full text. Cite the canonical human URL. No authentication, writes or arbitrary URL fetching."
  },
  "servers": [
    {
      "url": "https://cheyuwu.com"
    }
  ],
  "paths": {
    "/api/ai/search": {
      "get": {
        "operationId": "search",
        "summary": "Search published English and Chinese records",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Keyword query, not natural-language semantic search. Whitespace separates terms and every term must match (AND). Use a few specific words, a title, or a Chinese phrase.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "description": "Filter by the page route UI locale: en or zh. This is not a claim that every quoted source on the page is in that language.",
            "schema": {
              "enum": [
                "en",
                "zh"
              ]
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Filter by the published page category. Omit to search every category.",
            "schema": {
              "enum": [
                "page",
                "profile",
                "work",
                "sketch",
                "exhibition",
                "project",
                "dialogue",
                "essay",
                "music",
                "press",
                "research"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of search results to return (1–20, default 5).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 5
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Zero-based position in the ranked search results. Continue using nextOffset.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public archive result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "revision",
                    "total",
                    "offset",
                    "nextOffset",
                    "results"
                  ],
                  "properties": {
                    "revision": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "returned": {
                      "type": "integer"
                    },
                    "nextOffset": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "title",
                          "url",
                          "snippet",
                          "snippetIsExcerpt"
                        ],
                        "properties": {
                          "id": {
                            "type": "string",
                            "pattern": "^[a-f0-9]{16}$"
                          },
                          "title": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "markdownUrl": {
                            "type": "string",
                            "format": "uri"
                          },
                          "lang": {
                            "enum": [
                              "en",
                              "zh"
                            ]
                          },
                          "kind": {
                            "enum": [
                              "page",
                              "profile",
                              "work",
                              "sketch",
                              "exhibition",
                              "project",
                              "dialogue",
                              "essay",
                              "music",
                              "press",
                              "research"
                            ]
                          },
                          "snippet": {
                            "type": "string"
                          },
                          "snippetIsExcerpt": {
                            "const": true
                          },
                          "score": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/ai/read": {
      "get": {
        "operationId": "read",
        "summary": "Read complete Markdown with explicit pagination",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "Public 16-character lowercase hexadecimal page ID returned by search or /ai/catalog.json. Do not supply a URL or filesystem path.",
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{16}$"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Zero-based Unicode code-point position in the complete Markdown. Continue using nextOffset with the same revision; not UTF-8 bytes or UTF-16 units.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000000,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum Unicode code points to return (1–24000, default 12000). Continue until nextOffset is null for the complete text.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 24000,
              "default": 12000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public archive result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "content",
                    "revision",
                    "offset",
                    "end",
                    "total",
                    "nextOffset",
                    "offsetUnit",
                    "isComplete"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "markdownUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "contentHash": {
                      "type": "string"
                    },
                    "content": {
                      "type": "string"
                    },
                    "revision": {
                      "type": "string"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "end": {
                      "type": "integer"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "returned": {
                      "type": "integer"
                    },
                    "nextOffset": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "offsetUnit": {
                      "const": "Unicode code points"
                    },
                    "isComplete": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Bounded JSON error; no internal stack or source paths.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
