{
  "openapi": "3.0.3",
  "info": {
    "title": "Lim Chee Kin Portfolio API",
    "version": "2.2.0",
    "description": "Static portfolio API providing structured data about Lim Chee Kin's projects, work experience, and articles. All responses are pre-generated at build time.",
    "contact": {
      "name": "Lim Chee Kin",
      "email": "limcheekin@vobject.com",
      "url": "https://kin.rag.wtf"
    },
    "license": {
      "name": "MIT",
      "url": "https://github.com/limcheekin/portfolio/blob/main/LICENSE"
    },
    "x-mcp-server": {
      "url": "https://kin.rag.wtf/mcp",
      "transport": "streamable-http",
      "authentication": "none",
      "manifest": "https://kin.rag.wtf/.well-known/mcp.json"
    }
  },
  "servers": [
    {
      "url": "https://kin.rag.wtf",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/": {
      "get": {
        "summary": "API index",
        "operationId": "getApiIndex",
        "description": "The endpoints of this API, with the MCP server and llms.txt.",
        "tags": [
          "Portfolio"
        ],
        "responses": {
          "200": {
            "description": "API index",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiIndex"
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/Cache-Control"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Window": {
                "$ref": "#/components/headers/X-RateLimit-Window"
              },
              "X-RateLimit-Policy": {
                "$ref": "#/components/headers/X-RateLimit-Policy"
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    },
    "/api/portfolio.json": {
      "get": {
        "summary": "Get full portfolio data",
        "operationId": "getPortfolio",
        "description": "Returns all portfolio data including name, title, contact URLs, projects, work experience history, and articles.",
        "tags": [
          "Portfolio"
        ],
        "responses": {
          "200": {
            "description": "Full portfolio data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Portfolio"
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/Cache-Control"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Window": {
                "$ref": "#/components/headers/X-RateLimit-Window"
              },
              "X-RateLimit-Policy": {
                "$ref": "#/components/headers/X-RateLimit-Policy"
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    },
    "/llms-full.txt": {
      "get": {
        "summary": "Full portfolio content as plain text",
        "operationId": "getLlmsFullText",
        "description": "Returns all portfolio content (projects with full descriptions, work experience, articles) as a structured plain-text document optimised for LLM consumption.",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "Plain text portfolio content",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    },
    "/llms.txt": {
      "get": {
        "summary": "LLM-readable site index",
        "operationId": "getLlmsTxt",
        "description": "Structured markdown index of the portfolio site for LLM agents, following the llms.txt convention.",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "Structured markdown index",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    },
    "/api/projects.json": {
      "get": {
        "summary": "Get projects only",
        "operationId": "getProjects",
        "description": "Returns only the projects array from the portfolio.",
        "tags": [
          "Portfolio"
        ],
        "responses": {
          "200": {
            "description": "Array of projects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Project"
                  }
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/Cache-Control"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Window": {
                "$ref": "#/components/headers/X-RateLimit-Window"
              },
              "X-RateLimit-Policy": {
                "$ref": "#/components/headers/X-RateLimit-Policy"
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    },
    "/api/experience.json": {
      "get": {
        "summary": "Get work experience only",
        "operationId": "getExperience",
        "description": "Returns only the work experience array from the portfolio.",
        "tags": [
          "Portfolio"
        ],
        "responses": {
          "200": {
            "description": "Array of experience entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Experience"
                  }
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/Cache-Control"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Window": {
                "$ref": "#/components/headers/X-RateLimit-Window"
              },
              "X-RateLimit-Policy": {
                "$ref": "#/components/headers/X-RateLimit-Policy"
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    },
    "/api/articles.json": {
      "get": {
        "summary": "Get articles only",
        "operationId": "getArticles",
        "description": "Returns only the articles array from the portfolio.",
        "tags": [
          "Portfolio"
        ],
        "responses": {
          "200": {
            "description": "Array of articles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Article"
                  }
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/Cache-Control"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Window": {
                "$ref": "#/components/headers/X-RateLimit-Window"
              },
              "X-RateLimit-Policy": {
                "$ref": "#/components/headers/X-RateLimit-Policy"
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    },
    "/api/search.json": {
      "get": {
        "summary": "Search index",
        "operationId": "getSearchIndex",
        "description": "Every project, article and role in one flat list with keywords and its page URL. Filter it client-side; the MCP tool search_portfolio does the same server-side.",
        "tags": [
          "Portfolio"
        ],
        "responses": {
          "200": {
            "description": "Search index",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchIndex"
                }
              }
            },
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Last-Modified": {
                "$ref": "#/components/headers/Last-Modified"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/Cache-Control"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Window": {
                "$ref": "#/components/headers/X-RateLimit-Window"
              },
              "X-RateLimit-Policy": {
                "$ref": "#/components/headers/X-RateLimit-Policy"
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Portfolio": {
        "type": "object",
        "description": "Complete portfolio data for Lim Chee Kin",
        "properties": {
          "name": {
            "type": "string",
            "example": "Lim Chee Kin"
          },
          "title": {
            "type": "string",
            "example": "AI Solutions Architect"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "limcheekin@vobject.com"
          },
          "urls": {
            "type": "object",
            "properties": {
              "github": {
                "type": "string",
                "format": "uri"
              },
              "linkedin": {
                "type": "string",
                "format": "uri"
              },
              "medium": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "projects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Project"
            }
          },
          "articles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Article"
            }
          },
          "experience": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Experience"
            }
          },
          "metadata": {
            "type": "object",
            "properties": {
              "generatedAt": {
                "type": "string",
                "format": "date-time"
              },
              "version": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "name",
          "title",
          "email",
          "urls",
          "projects",
          "articles",
          "experience",
          "metadata"
        ]
      },
      "Project": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Project page on kin.rag.wtf"
          },
          "summary": {
            "type": "string",
            "maxLength": 160,
            "description": "One sentence that names the project (the page's meta description)"
          },
          "description": {
            "type": "string"
          },
          "featured": {
            "type": "boolean"
          },
          "kind": {
            "type": "string",
            "enum": [
              "enterprise",
              "oss"
            ],
            "description": "enterprise: closed systems built at Daxonet AI (no repository or live link); oss: open-source work"
          },
          "org": {
            "type": "string",
            "description": "Organisation an enterprise project was built for"
          },
          "tagline": {
            "type": "string",
            "description": "One-line outcome shown on the project card"
          },
          "technologies": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "githubUrl": {
            "type": "string",
            "format": "uri"
          },
          "liveUrl": {
            "type": "string",
            "format": "uri"
          },
          "category": {
            "type": "string"
          }
        },
        "required": [
          "title",
          "slug",
          "url",
          "summary",
          "description",
          "featured",
          "kind",
          "technologies"
        ]
      },
      "Article": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Summary page on kin.rag.wtf"
          },
          "description": {
            "type": "string"
          },
          "externalUrl": {
            "type": "string",
            "format": "uri"
          },
          "publishDate": {
            "type": "string",
            "format": "date-time"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "title",
          "slug",
          "url",
          "description",
          "publishDate",
          "tags"
        ]
      },
      "Experience": {
        "type": "object",
        "properties": {
          "company": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "startDate": {
            "type": "string",
            "description": "YYYY-MM",
            "example": "2026-01"
          },
          "endDate": {
            "type": "string",
            "description": "YYYY-MM; absent for the current role"
          },
          "description": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Responsibilities and outcomes, one per item"
          },
          "technologies": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "company",
          "title",
          "startDate",
          "description",
          "technologies"
        ]
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "example": "not_found"
          },
          "message": {
            "type": "string"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "SearchIndex": {
        "type": "object",
        "properties": {
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "project",
                    "article",
                    "experience"
                  ]
                },
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Page on kin.rag.wtf (roles: an anchor on /about/)"
                },
                "summary": {
                  "type": "string"
                },
                "keywords": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "date": {
                  "type": "string",
                  "description": "Publish date (articles, ISO 8601) or start month (roles, YYYY-MM)"
                }
              },
              "required": [
                "type",
                "title",
                "url",
                "summary",
                "keywords"
              ]
            }
          }
        },
        "required": [
          "generatedAt",
          "items"
        ]
      },
      "ApiIndex": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "description": {
                  "type": "string"
                }
              },
              "required": [
                "url",
                "description"
              ]
            }
          },
          "mcp": {
            "type": "string",
            "format": "uri"
          },
          "llms": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "name",
          "version",
          "endpoints"
        ]
      }
    },
    "headers": {
      "ETag": {
        "description": "Entity tag; send it back in If-None-Match for a conditional GET",
        "schema": {
          "type": "string"
        }
      },
      "Last-Modified": {
        "description": "Build time of the deployed data",
        "schema": {
          "type": "string"
        }
      },
      "Cache-Control": {
        "description": "public, max-age=3600, must-revalidate",
        "schema": {
          "type": "string"
        }
      },
      "X-RateLimit-Limit": {
        "description": "Advisory: requests per window (not enforced)",
        "schema": {
          "type": "integer",
          "example": 60
        }
      },
      "X-RateLimit-Window": {
        "description": "Advisory window in seconds",
        "schema": {
          "type": "integer",
          "example": 60
        }
      },
      "X-RateLimit-Policy": {
        "description": "Advisory policy in the IETF RateLimit draft form, quota;w=window (not enforced)",
        "schema": {
          "type": "string",
          "example": "60;w=60"
        }
      }
    },
    "responses": {
      "NotModified": {
        "description": "Not modified since the ETag sent in If-None-Match"
      },
      "NotFound": {
        "description": "No such resource",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "parameters": {
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "required": false,
        "description": "ETag from a previous response",
        "schema": {
          "type": "string"
        }
      }
    }
  },
  "externalDocs": {
    "description": "Agent index (llms.txt), including the MCP server",
    "url": "https://kin.rag.wtf/llms.txt"
  }
}
