openapi: 3.1.0
info:
  title: Agent Inspector Named Instance Control API
  version: 1.0.0
  description: |
    Local control-plane API for discovering and managing Windows named Agent Inspector instances.
    Paths are relative to the selected backend control Base URL. Loopback clients are trusted by the
    native ingress; direct non-loopback clients must send the configured control Bearer token.
    Browser mutations also require same-origin CSRF proof. A reverse proxy whose upstream appears
    as loopback must authenticate its own remote clients.
servers:
  - url: http://127.0.0.1:9527
    description: Root-mounted controller example
  - url: http://127.0.0.1:9530/inspector
    description: Prefixed named-instance controller example
tags:
  - name: Instances
paths:
  /api/instances:
    get:
      tags: [Instances]
      operationId: listNamedInstances
      summary: List registered named instances and derived live state
      responses:
        "200":
          description: Versioned instance list
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InstanceList"
        default:
          $ref: "#/components/responses/InstanceError"
  /api/instances/{name}:
    parameters:
      - $ref: "#/components/parameters/InstanceName"
    get:
      tags: [Instances]
      operationId: getNamedInstance
      summary: Read one named instance and its live state
      responses:
        "200":
          description: Instance view
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InstanceView"
        default:
          $ref: "#/components/responses/InstanceError"
  /api/instances/{name}/connection:
    parameters:
      - $ref: "#/components/parameters/InstanceName"
    get:
      tags: [Instances]
      operationId: getNamedInstanceConnection
      summary: Read protocol-correct Coding Agent connection settings
      responses:
        "200":
          description: Token-free connection descriptor
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InstanceConnection"
        default:
          $ref: "#/components/responses/InstanceError"
  /api/instances/{name}/start:
    parameters:
      - $ref: "#/components/parameters/InstanceName"
    post:
      tags: [Instances]
      operationId: startNamedInstance
      summary: Idempotently create, start, or reuse a named instance
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InstanceStartRequest"
      responses:
        "200":
          description: Existing instance started or reused
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InstanceOperation"
        "201":
          description: New instance record created and started
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InstanceOperation"
        default:
          $ref: "#/components/responses/InstanceError"
  /api/instances/{name}/stop:
    parameters:
      - $ref: "#/components/parameters/InstanceName"
    post:
      tags: [Instances]
      operationId: stopNamedInstance
      summary: Gracefully stop a matching sibling instance
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
      responses:
        "200":
          description: Instance stopped or already stopped
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InstanceOperation"
        default:
          $ref: "#/components/responses/InstanceError"
  /api/instances/{name}/restart:
    parameters:
      - $ref: "#/components/parameters/InstanceName"
    post:
      tags: [Instances]
      operationId: restartNamedInstance
      summary: Validate configuration, gracefully stop, and relaunch a sibling instance
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InstanceStartRequest"
      responses:
        "200":
          description: Replacement launch reached readiness
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InstanceOperation"
        default:
          $ref: "#/components/responses/InstanceError"
components:
  securitySchemes:
    controlBearer:
      type: http
      scheme: bearer
      description: Value of AGENT_INSPECTOR_CONTROL_TOKEN for direct non-loopback access.
  parameters:
    InstanceName:
      name: name
      in: path
      required: true
      schema:
        type: string
        pattern: "^[a-z0-9._-]{1,64}$"
      example: review
  responses:
    InstanceError:
      description: Versioned machine-readable lifecycle error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/InstanceError"
  schemas:
    InstanceUrls:
      type: object
      additionalProperties: false
      required: [ui, api, health, proxy, openai, mcp]
      properties:
        ui: { type: string, format: uri, example: "http://127.0.0.1:9530/inspector" }
        api: { type: string, format: uri, example: "http://127.0.0.1:9530/inspector/api" }
        health:
          { type: string, format: uri, example: "http://127.0.0.1:9530/inspector/api/health" }
        proxy:
          { type: string, format: uri, example: "http://127.0.0.1:9530/inspector/proxy" }
        openai:
          { type: string, format: uri, example: "http://127.0.0.1:9530/inspector/proxy/v1" }
        mcp:
          { type: string, format: uri, example: "http://127.0.0.1:9530/inspector/api/mcp" }
    InstanceView:
      type: object
      additionalProperties: false
      required:
        - schemaVersion
        - name
        - instanceId
        - state
        - stateReason
        - checkedAt
        - createdAt
        - updatedAt
        - launch
        - host
        - publicPort
        - upstreamPort
        - basePath
        - captureMode
        - uiEnabled
        - dataDir
        - supervisorPid
        - urls
      properties:
        schemaVersion: { const: 1 }
        name: { type: string, example: review }
        instanceId: { type: string, example: "d8805ce7-5ec7-41fb-a370-c56b57418839" }
        state: { type: string, enum: [running, stopped, conflict] }
        stateReason:
          oneOf:
            - { type: string, enum: [identity_mismatch, port_conflict] }
            - { type: "null" }
        checkedAt: { type: string, format: date-time }
        createdAt: { type: string, format: date-time }
        updatedAt: { type: string, format: date-time }
        launch:
          type: object
          additionalProperties: false
          required: [launchId, startedAt]
          properties:
            launchId: { type: string }
            startedAt: { type: string, format: date-time }
        host: { type: string, example: "127.0.0.1" }
        publicPort: { type: integer, minimum: 1, maximum: 65535, example: 9530 }
        upstreamPort: { type: integer, minimum: 1, maximum: 65535, example: 9532 }
        basePath: { type: string, example: /inspector }
        captureMode: { type: string, enum: [simple, full] }
        uiEnabled:
          type: boolean
          description: Whether this instance serves the composed Web UI. Backend endpoints remain available when false.
        dataDir: { type: string, example: "C:\\Users\\me\\AppData\\Local\\agent-inspector\\instances\\review\\data" }
        supervisorPid:
          oneOf:
            - { type: integer, minimum: 1 }
            - { type: "null" }
        urls:
          $ref: "#/components/schemas/InstanceUrls"
    InstanceList:
      type: object
      additionalProperties: false
      required: [schemaVersion, instances]
      properties:
        schemaVersion: { const: 1 }
        instances:
          type: array
          items:
            $ref: "#/components/schemas/InstanceView"
    InstanceStartRequest:
      type: object
      additionalProperties: false
      properties:
        port: { type: integer, minimum: 1, maximum: 65535 }
        basePath: { type: string, example: /inspector }
        host: { type: string, example: "127.0.0.1" }
        captureMode: { type: string, enum: [simple, full] }
        uiEnabled:
          type: boolean
          description: Persist composed UI serving when true or backend-only mode when false.
        dataDir: { type: string }
    InstanceOperation:
      type: object
      additionalProperties: false
      required: [schemaVersion, operation, outcome, instance]
      properties:
        schemaVersion: { const: 1 }
        operation: { type: string, enum: [start, stop, restart] }
        outcome:
          type: string
          enum: [created, started, already_running, stopped, already_stopped, restarted]
        instance:
          $ref: "#/components/schemas/InstanceView"
    InstanceConnectionSurfaces:
      type: object
      additionalProperties: false
      required: [ui, control, agent]
      properties:
        ui:
          type: object
          additionalProperties: false
          required: [enabled, baseUrl]
          properties:
            enabled:
              type: boolean
              description: Whether this instance serves its composed Web UI.
            baseUrl:
              description: Composed UI Base URL, or null for a backend-only instance.
              oneOf:
                - { type: string, format: uri }
                - { type: "null" }
        control:
          type: object
          additionalProperties: false
          required: [baseUrl]
          properties:
            baseUrl:
              type: string
              format: uri
              description: Base URL for REST, mutation, upload/download, and SSE traffic.
        agent:
          type: object
          additionalProperties: false
          required: [baseUrl]
          properties:
            baseUrl:
              type: string
              format: uri
              description: Base URL from which proxy and MCP client endpoints are derived.
    InstanceConnection:
      type: object
      additionalProperties: false
      required: [schemaVersion, uiEnabled, instance, surfaces, baseUrl, endpoints, environment, mcp, codex]
      properties:
        schemaVersion: { const: 1 }
        uiEnabled:
          type: boolean
          description: Whether the instance currently serves its composed Web UI; proxy, REST, health, and MCP remain valid when false.
        instance: { $ref: "#/components/schemas/InstanceView" }
        surfaces: { $ref: "#/components/schemas/InstanceConnectionSurfaces" }
        baseUrl:
          type: string
          format: uri
          deprecated: true
          description: Legacy backend Base URL; use surfaces.control.baseUrl or surfaces.agent.baseUrl.
        endpoints:
          allOf:
            - { $ref: "#/components/schemas/InstanceUrls" }
          deprecated: true
          description: Legacy derived endpoint set retained for compatibility; use surfaces for Base URLs.
        environment:
          type: object
          additionalProperties: false
          required: [ANTHROPIC_BASE_URL, LLM_BASE_URL, OPENAI_BASE_URL, AGENT_INSPECTOR_MCP_URL]
          properties:
            ANTHROPIC_BASE_URL: { type: string, format: uri }
            LLM_BASE_URL: { type: string, format: uri }
            OPENAI_BASE_URL: { type: string, format: uri }
            AGENT_INSPECTOR_MCP_URL: { type: string, format: uri }
        mcp:
          type: object
          additionalProperties: false
          required: [serverName, transport, url]
          properties:
            serverName: { type: string, example: agent-inspector-review }
            transport: { const: streamable-http }
            url: { type: string, format: uri }
        codex:
          type: object
          additionalProperties: false
          required: [providerName, baseUrl, wireApi]
          properties:
            providerName: { type: string, example: agent-inspector-review }
            baseUrl: { type: string, format: uri }
            wireApi: { const: responses }
    InstanceError:
      type: object
      additionalProperties: false
      required: [schemaVersion, error]
      properties:
        schemaVersion: { const: 1 }
        error:
          type: object
          additionalProperties: false
          required: [code, message, retryable]
          properties:
            code: { type: string }
            message: { type: string }
            retryable: { type: boolean }
