openapi: "3.1.0"
info:
  title: "AI Dev Hub Unified OpenAPI"
  version: "1.0.0"
  description: "Unified index for AI Dev Hub runtime and dedicated API specs."
servers:
  - url: "https://aidevhub.io"
    description: "Primary hub runtime"
paths:
  /api/skills-index.json:
    get:
      summary: "Agent skills bundle index"
      operationId: "skillsIndex"
      responses:
        "200":
          description: "Skills index"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SkillsIndex"
  /api/skills-bundle.json:
    get:
      summary: "Agent skills bundle payload"
      operationId: "skillsBundle"
      responses:
        "200":
          description: "Skills bundle"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SkillsBundle"
  /api/tools/run/:
    get:
      summary: "Execute server-enabled tool (GET)"
      operationId: "runToolGet"
      parameters:
        - in: query
          name: toolId
          required: true
          schema: { type: string }
        - in: query
          name: a
          required: false
          schema: { type: string }
        - in: query
          name: b
          required: false
          schema: { type: string }
        - in: query
          name: c
          required: false
          schema: { type: string }
        - in: query
          name: mode
          required: false
          schema: { type: string }
      responses:
        "200":
          description: "Tool result"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunSuccess"
        "400":
          description: "Invalid input"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
        "413":
          description: "Payload too large"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
        "429":
          description: "Rate limit exceeded"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
        "503":
          description: "Runtime disabled by policy"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
    post:
      summary: "Execute server-enabled tool (POST)"
      operationId: "runToolPost"
      description: |
        Accepts two equivalent body shapes:
        - **Nested** (canonical): `{"toolId":"…","source":"…","input":{"a":"…","b":"…","c":"…","mode":"…"}}`
        - **Flat** (convenience): `{"toolId":"…","source":"…","a":"…","b":"…","c":"…","mode":"…"}`
        The flat shape is auto-detected when the top-level `input` key is absent.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - title: "Nested input (canonical)"
                  type: object
                  properties:
                    toolId: { type: string }
                    source: { type: string, enum: [web, api, mcp, direct_framework] }
                    input:
                      type: object
                      properties:
                        a: { type: string }
                        b: { type: string }
                        c: { type: string }
                        mode: { type: string }
                  required: [toolId, input]
                - title: "Flat input (convenience)"
                  type: object
                  properties:
                    toolId: { type: string }
                    source: { type: string, enum: [web, api, mcp, direct_framework] }
                    a: { type: string }
                    b: { type: string }
                    c: { type: string }
                    mode: { type: string }
                  required: [toolId, a]
      responses:
        "200":
          description: "Tool result"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunSuccess"
        "400":
          description: "Invalid input"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
        "413":
          description: "Payload too large"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
        "429":
          description: "Rate limit exceeded"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
        "503":
          description: "Runtime disabled by policy"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ToolRunError"
components:
  schemas:
    SkillsIndex:
      type: object
      properties:
        generatedAt: { type: string, format: date-time }
        version: { type: string }
        toolCount: { type: integer }
        commonFiles:
          type: array
          items: { type: string }
        tools:
          type: array
          items:
            type: object
            properties:
              toolId: { type: string }
              modeLabel: { type: string }
              remoteMode: { type: string }
              remoteCallable: { type: boolean }
              riskClass: { type: string }
            required: [toolId, modeLabel, remoteMode, remoteCallable, riskClass]
      required: [generatedAt, version, toolCount, commonFiles, tools]
    SkillsBundle:
      type: object
      properties:
        generatedAt: { type: string, format: date-time }
        version: { type: string }
        toolCount: { type: integer }
        common:
          type: object
          properties:
            errorHandling: { type: string }
            invocationPatterns: { type: string }
            safetyDefaults: { type: string }
          required: [errorHandling, invocationPatterns, safetyDefaults]
        tools:
          type: array
          items:
            type: object
            properties:
              toolId: { type: string }
              modeLabel: { type: string }
              remoteMode: { type: string }
              riskClass: { type: string }
              remoteCallable: { type: boolean }
              files:
                type: object
                properties:
                  skillMd: { type: string }
                  examples:
                    type: object
                    properties:
                      basic: { type: object, additionalProperties: true }
                      edgeCase: { type: object, additionalProperties: true }
                      expectedOutput: { type: object, additionalProperties: true }
                    required: [basic, edgeCase, expectedOutput]
                required: [skillMd, examples]
            required: [toolId, modeLabel, remoteMode, riskClass, remoteCallable, files]
      required: [generatedAt, version, toolCount, common, tools]
    ToolRunSuccess:
      type: object
      properties:
        ok:
          type: boolean
          const: true
        result:
          type: object
          additionalProperties: true
        runtime:
          type: object
          additionalProperties: true
      required: [ok, result]
    ToolRunError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
        error:
          type: string
        errorCode:
          type: string
          enum:
            - INVALID_INPUT
            - INPUT_TOO_LARGE
            - TIMEOUT
            - UNSUPPORTED_OPTION
            - INTERNAL_ERROR
            - RATE_LIMITED
            - RUNTIME_DISABLED
            - TOOL_DISABLED
            - TOOL_WRONG_SURFACE
            - BUDGET_EXCEEDED
            - CONCURRENCY_LIMIT
        rateLimit:
          type: object
          additionalProperties: true
        runtime:
          type: object
          additionalProperties: true
      required: [ok, error, errorCode]
x-dedicatedOpenAPI:
  - slug: "token-counter"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/token-counter/"
  - slug: "schema-validator"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/schema-validator/"
  - slug: "schema-generator"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/schema-generator/"
  - slug: "format-detective"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/format-detective/detect/"
      - "/api/format-detective/convert/"
  - slug: "structured-diff"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/structured-diff/"
  - slug: "cron-expression"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/cron-expression/parse/"
      - "/api/cron-expression/build/"
  - slug: "regex-tester"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/regex-tester/"
  - slug: "qr-code"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/qr-code/"
  - slug: "color-palette"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/color-palette/generate/"
      - "/api/color-palette/convert/"
  - slug: "html-markdown"
    openapiUrl: "https://aidevhub.io/api/openapi.yaml"
    serverUrl: "https://aidevhub.io"
    paths:
      - "/api/html-markdown/"
