# AUTO-GENERATED by scripts/generate-openapi.js from static/knowledge-graph.json — do not edit by hand.
# Endpoints, query enums and params are derived from the graph's self-documentation.
openapi: "3.1.0"
info:
  title: "Andros Guiradó Portfolio API"
  description: "API for accessing Andros Guiradó’s professional portfolio. Generated from the knowledge graph (knowledge-graph.json) — the single source of truth. Human/agent index: https://androsguirado.dev/machine-readable."
  version: "1.1.0"
  contact:
    email: "andros.guirado@feelslike.studio"
servers:
  - url: "https://androsguirado.dev"
    description: "Production server"
paths:
  "/knowledge-graph.json":
    get:
      operationId: "getKnowledgeGraph"
      summary: "Projects, clients, skills, timeline and relationships — the single source of truth."
      responses:
        "200":
          description: "Canonical machine-readable representation of the complete portfolio: normalized nodes (Person, Project, Client, Skill, Organization, Event, Award) and explicit typed edges (WORKED_ON, USED_SKILL, FOR_CLIENT, BUILT_AT, SPOKE_AT, AWARDED_FOR…). Self-documented in its meta block; every other dataset here is derived from it."
          content:
            "application/json":
              schema:
                type: "object"
  "/kg-query.js":
    get:
      operationId: "getKnowledgeGraphQueryEngine"
      summary: "Answer relationship questions without loading the whole graph."
      responses:
        "200":
          description: "Declarative query layer over the graph (browser + Node). Named, explainable queries — projects_by_year, projects_by_client, skills_by_project, clients_by_skill, projects_by_skill, skills_evolution, projects_by_relevance — each with a per-step traversal trace."
          content:
            "application/javascript":
              schema:
                type: "string"
  "/seo.json":
    get:
      operationId: "getSEOManifest"
      summary: "Rich results and structured data for search engines."
      responses:
        "200":
          description: "The full career timeline as a schema.org @graph (WebSite, ProfilePage, Person, CreativeWork projects). A compact ProfilePage/Person snippet is also inlined into every HTML page, which is what search engines actually parse."
          content:
            "application/ld+json":
              schema:
                type: "object"
  "/llms.txt":
    get:
      operationId: "getLlmsTxt"
      summary: "Fast, low-token grounding for language models."
      responses:
        "200":
          description: "Concise, LLM-oriented profile following the llms.txt convention: bio, career timeline, skills, awards, talks, and a curated index of every machine-readable resource."
          content:
            "text/markdown":
              schema:
                type: "string"
  "/llms-full.txt":
    get:
      operationId: "getLlmsFullTxt"
      summary: "Everything about the portfolio in a single request."
      responses:
        "200":
          description: "The entire profile expanded into one self-contained document — complete skills inventory, full client list, every award and talk, and the full year-by-year timeline."
          content:
            "text/markdown":
              schema:
                type: "string"
  "/timeline.json":
    get:
      operationId: "getTimelineJSON"
      summary: "Chronological data ready to render or analyse."
      responses:
        "200":
          description: "Year-by-year activity — career steps, studio milestones, talks, awards and projects, with skills, roles and project types resolved by name."
          content:
            "application/json":
              schema:
                type: "object"
  "/timeline.md":
    get:
      operationId: "getTimelineMarkdown"
      summary: "Human- and LLM-readable chronology."
      responses:
        "200":
          description: "The same year-by-year timeline in LLM-friendly Markdown."
          content:
            "text/markdown":
              schema:
                type: "string"
  "/.well-known/openapi.yaml":
    get:
      operationId: "getOpenAPISpecification"
      summary: "Auto-generate clients and let agents discover the API."
      responses:
        "200":
          description: "Full machine-readable contract for the REST API and content endpoints."
          content:
            "application/yaml":
              schema:
                type: "string"
  "/.well-known/ai-plugin.json":
    get:
      operationId: "getAIPluginManifest"
      summary: "Plugin-style discovery for AI assistants."
      responses:
        "200":
          description: "Plugin manifest describing the portfolio and pointing to the OpenAPI spec."
          content:
            "application/json":
              schema:
                type: "object"
  "/.well-known/agent-skills/index.json":
    get:
      operationId: "getAgentSkills"
      summary: "Skill-based discovery for agent frameworks."
      responses:
        "200":
          description: "Agent Skills index exposing a portfolio-info skill with a content hash for integrity."
          content:
            "application/json":
              schema:
                type: "object"
  "/.well-known/api-catalog":
    get:
      operationId: "getAPICatalog"
      summary: "Standards-based API discovery (RFC 8615 / RFC 9727)."
      responses:
        "200":
          description: "Standard linkset (RFC 9727) pointing to the service description (OpenAPI), the human/agent index and the documentation (llms.txt)."
          content:
            "application/linkset+json":
              schema:
                type: "object"
  "/sitemap.xml":
    get:
      operationId: "getSitemap"
      summary: "Crawl coverage for search engines."
      responses:
        "200":
          description: "XML sitemap of all crawlable pages."
          content:
            "application/xml":
              schema:
                type: "string"
  "/robots.txt":
    get:
      operationId: "getRobotsTxt"
      summary: "Tell crawlers and AI bots what they may use."
      responses:
        "200":
          description: "Crawl directives, explicit allow-list for AI crawlers, sitemap reference and Content-Signal declarations."
          content:
            "text/plain":
              schema:
                type: "string"
  "/api/markdown":
    get:
      operationId: "getMarkdown"
      summary: "Get site content as Markdown (content-negotiated; also served at / via Accept: text/markdown)."
      responses:
        "200":
          description: "Full portfolio content in Markdown format"
          content:
            "text/markdown":
              schema:
                type: "string"
  "/api/status":
    get:
      operationId: "getStatus"
      summary: "Health & freshness probe: API liveness, knowledge-graph version (= X-KG-Version), schemaVersion, lastUpdated and live entity/relationship counts. Also aliased at /status."
      responses:
        "200":
          description: "Service status and knowledge-graph version metadata"
          content:
            "application/json":
              schema:
                type: "object"
  "/api/kg/nodes":
    get:
      operationId: "listNodes"
      summary: "List or filter knowledge-graph entities (nodes)."
      parameters:
        - name: "type"
          in: "query"
          schema:
            type: "string"
            enum:
              - "Person"
              - "Skill"
              - "Project"
              - "Organization"
              - "Client"
              - "Event"
              - "Award"
          description: "Node type"
        - name: "q"
          in: "query"
          schema:
            type: "string"
          description: "Fuzzy name/alias search (accent and case insensitive)"
        - name: "limit"
          in: "query"
          schema:
            type: "integer"
            default: 100
            maximum: 1000
          description: "Max results"
        - name: "offset"
          in: "query"
          schema:
            type: "integer"
            default: 0
          description: "Pagination offset"
      responses:
        "200":
          description: "Paginated entity list with total and entityTypes index"
          content:
            "application/json":
              schema:
                type: "object"
  "/api/kg/edges":
    get:
      operationId: "listEdges"
      summary: "List or filter knowledge-graph relationships (edges)."
      parameters:
        - name: "type"
          in: "query"
          schema:
            type: "string"
            enum:
              - "KNOWS_SKILL"
              - "WORKED_ON"
              - "BUILT_AT"
              - "USED_SKILL"
              - "VIA_AGENCY"
              - "FOR_CLIENT"
              - "PARTICIPATED_IN"
              - "AT"
              - "SPOKE_AT"
              - "RECEIVED"
              - "AWARDED_FOR"
          description: "Edge type"
        - name: "from"
          in: "query"
          schema:
            type: "string"
          description: "Source entity id"
        - name: "to"
          in: "query"
          schema:
            type: "string"
          description: "Target entity id"
        - name: "limit"
          in: "query"
          schema:
            type: "integer"
            default: 100
            maximum: 1000
          description: "Max results"
        - name: "offset"
          in: "query"
          schema:
            type: "integer"
            default: 0
          description: "Pagination offset"
      responses:
        "200":
          description: "Paginated edge list with total and relationshipTypes index"
          content:
            "application/json":
              schema:
                type: "object"
  "/api/kg/query":
    get:
      operationId: "queryKnowledgeGraph"
      summary: "Run a declarative query over the knowledge graph (returns results + per-step traversal trace)."
      parameters:
        - name: "type"
          in: "query"
          required: true
          schema:
            type: "string"
            enum:
              - "projects_by_year"
              - "projects_by_client"
              - "skills_by_project"
              - "clients_by_skill"
              - "projects_by_skill"
              - "skills_evolution"
              - "projects_by_relevance"
          description: "Query name"
        - name: "explain"
          in: "query"
          schema:
            type: "boolean"
          description: "Return only the traversal plan, without executing"
        - name: "year"
          in: "query"
          schema:
            type: "integer"
          description: "int — single year"
        - name: "from"
          in: "query"
          schema:
            type: "integer"
          description: "int — range start (alt. to year)"
        - name: "to"
          in: "query"
          schema:
            type: "integer"
          description: "int — range end"
        - name: "client"
          in: "query"
          schema:
            type: "string"
          description: "entity id or name, e.g. \"Volkswagen\" or \"client_volkswagen\""
        - name: "project"
          in: "query"
          schema:
            type: "string"
          description: "entity id or name, e.g. \"Beetle dream\""
        - name: "skill"
          in: "query"
          schema:
            type: "string"
          description: "entity id or name, e.g. \"PHP\""
        - name: "min"
          in: "query"
          schema:
            type: "number"
          description: "float 0–1 — relevance threshold (default 0.7)"
      responses:
        "200":
          description: "Query results with per-step traversal trace"
          content:
            "application/json":
              schema:
                type: "object"
        "400":
          description: "Unknown query or missing params (response lists availableQueries)"
          content:
            "application/json":
              schema:
                type: "object"
  "/mcp":
    post:
      operationId: "mcpServer"
      summary: "MCP server (JSON-RPC 2.0, streamable HTTP, stateless). Methods: initialize, ping, tools/list, tools/call. Tools: getProjectsByYear, getProjectsByClient, getSkillsEvolution, queryKnowledgeGraph, searchEntities"
      requestBody:
        required: true
        content:
          "application/json":
            schema:
              type: "object"
      responses:
        "200":
          description: "JSON-RPC 2.0 response"
          content:
            "application/json":
              schema:
                type: "object"
        "202":
          description: "Notification acknowledged (no response body)"
