{
  "openapi": "3.1.0",
  "info": {
    "title": "Hacker Bob public records API",
    "version": "1.0.0",
    "summary": "Read-only access to cleared public Hacker Bob CVE records and capability metadata.",
    "description": "This API exposes only cleared public records. It cannot start assessments, interact with targets, access private workspaces, or spend credits. Assessment execution remains in the separately installed local Hacker Bob runtime. The major version is encoded in the URL. Breaking changes use a new major version. Deprecated versions publish Deprecation and Sunset headers with at least 90 days notice. Lifecycle policy: https://hackerbob.ai/api-policy.md.",
    "license": {
      "name": "Apache-2.0",
      "identifier": "Apache-2.0",
      "url": "https://www.apache.org/licenses/LICENSE-2.0"
    },
    "contact": {
      "name": "Hacker Bob security",
      "email": "security@hackerbob.ai",
      "url": "https://hackerbob.ai/contact"
    },
    "x-versioning-policy": {
      "strategy": "URL major version",
      "current": "v1",
      "deprecated": [],
      "policy": "https://hackerbob.ai/api-policy.md",
      "minimumSunsetNoticeDays": 90
    }
  },
  "externalDocs": {
    "description": "Hacker Bob public API reference",
    "url": "https://hackerbob.ai/api-reference"
  },
  "servers": [
    {
      "url": "https://hackerbob.ai",
      "description": "Public production records service"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Service",
      "description": "Service metadata and capability discovery."
    },
    {
      "name": "Public CVE records",
      "description": "Cleared vulnerability records from Michalis Vasileiadis's research portfolio; Hacker Bob's assistance varied by case."
    },
    {
      "name": "NLWeb",
      "description": "Natural-language search over the public record index."
    }
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "operationId": "getAgentApiHealth",
        "summary": "Check public records API health",
        "description": "Return the service version and its read-only execution boundary.",
        "tags": [
          "Service"
        ],
        "responses": {
          "200": {
            "description": "The public records API is available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            },
            "headers": {
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "429": {
            "description": "The edge request limit is exhausted. Retry after the advertised reset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The public records service could not complete the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "deprecated": false,
        "x-lifecycle": {
          "status": "active",
          "deprecationPolicy": "https://hackerbob.ai/api-policy.md",
          "minimumSunsetNoticeDays": 90
        }
      }
    },
    "/api/v1/capabilities": {
      "get": {
        "operationId": "getHackerBobCapabilities",
        "summary": "Get public interface capabilities",
        "description": "Return callable capabilities and the boundary separating public records from assessment execution.",
        "tags": [
          "Service"
        ],
        "responses": {
          "200": {
            "description": "Public capabilities and boundary metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Capabilities"
                }
              }
            },
            "headers": {
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "429": {
            "description": "The edge request limit is exhausted. Retry after the advertised reset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The public records service could not complete the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "deprecated": false,
        "x-lifecycle": {
          "status": "active",
          "deprecationPolicy": "https://hackerbob.ai/api-policy.md",
          "minimumSunsetNoticeDays": 90
        }
      }
    },
    "/api/v1/sandbox": {
      "get": {
        "operationId": "getPublicApiSandbox",
        "summary": "Inspect the public API contract sandbox",
        "description": "Return deterministic, non-persistent sandbox metadata and example requests. The sandbox does not execute assessments or expose production workspace data.",
        "tags": [
          "Service"
        ],
        "responses": {
          "200": {
            "description": "Sandbox boundaries, supported contract checks, and example requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sandbox"
                }
              }
            },
            "headers": {
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "429": {
            "description": "The edge request limit is exhausted. Retry after the advertised reset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The public records service could not complete the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "deprecated": false,
        "x-lifecycle": {
          "status": "active",
          "deprecationPolicy": "https://hackerbob.ai/api-policy.md",
          "minimumSunsetNoticeDays": 90
        }
      }
    },
    "/api/v1/cve-records": {
      "get": {
        "operationId": "listPublicCveRecords",
        "summary": "List public CVE records",
        "description": "List cleared public records with cursor pagination and optional exact project or status filters.",
        "tags": [
          "Public CVE records"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum records to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque cursor from the previous response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "project",
            "in": "query",
            "description": "Exact open-source project name.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Publication status.",
            "schema": {
              "$ref": "#/components/schemas/RecordStatus"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of public CVE records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CveRecordPage"
                }
              }
            },
            "headers": {
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The endpoint or public record does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "405": {
            "description": "The HTTP method is not supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "The edge request limit is exhausted. Retry after the advertised reset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The public records service could not complete the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "deprecated": false,
        "x-lifecycle": {
          "status": "active",
          "deprecationPolicy": "https://hackerbob.ai/api-policy.md",
          "minimumSunsetNoticeDays": 90
        }
      }
    },
    "/api/v1/cve-records/{recordId}": {
      "get": {
        "operationId": "getPublicCveRecord",
        "summary": "Get one public CVE record",
        "description": "Return one cleared public record by CVE identifier.",
        "tags": [
          "Public CVE records"
        ],
        "parameters": [
          {
            "name": "recordId",
            "in": "path",
            "required": true,
            "description": "CVE identifier.",
            "schema": {
              "type": "string",
              "pattern": "^CVE-[0-9]{4}-[0-9]+$",
              "examples": [
                "CVE-2026-47747"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The requested public CVE record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CveRecord"
                }
              }
            },
            "headers": {
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "404": {
            "description": "The endpoint or public record does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "The edge request limit is exhausted. Retry after the advertised reset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The public records service could not complete the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "deprecated": false,
        "x-lifecycle": {
          "status": "active",
          "deprecationPolicy": "https://hackerbob.ai/api-policy.md",
          "minimumSunsetNoticeDays": 90
        }
      }
    },
    "/api/v1/cve-records/batch": {
      "post": {
        "operationId": "batchGetPublicCveRecords",
        "summary": "Get multiple public CVE records",
        "description": "Return up to 50 public records in one side-effect-free request. The operation is idempotent and safe to retry.",
        "tags": [
          "Public CVE records"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Found records and requested identifiers without a public record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                }
              }
            },
            "headers": {
              "Link": {
                "$ref": "#/components/headers/Link"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The endpoint or public record does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "405": {
            "description": "The HTTP method is not supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "The edge request limit is exhausted. Retry after the advertised reset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The public records service could not complete the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "deprecated": false,
        "x-lifecycle": {
          "status": "active",
          "deprecationPolicy": "https://hackerbob.ai/api-policy.md",
          "minimumSunsetNoticeDays": 90
        }
      }
    },
    "/ask": {
      "get": {
        "operationId": "searchPublicRecordsWithNlweb",
        "summary": "Search public records using NLWeb",
        "description": "Search cleared public Hacker Bob records. Request text/event-stream or set stream=true for a Server-Sent Events response.",
        "tags": [
          "NLWeb"
        ],
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "description": "CVE identifier, project, or publication status to search.",
            "schema": {
              "type": "string",
              "default": "Hacker Bob public CVE records"
            }
          },
          {
            "name": "stream",
            "in": "query",
            "description": "Return Server-Sent Events when true.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "NLWeb list response or Server-Sent Events stream.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NlwebResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "The endpoint or public record does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "405": {
            "description": "The HTTP method is not supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "The edge request limit is exhausted. Retry after the advertised reset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "The public records service could not complete the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "deprecated": false,
        "x-lifecycle": {
          "status": "active",
          "deprecationPolicy": "https://hackerbob.ai/api-policy.md",
          "minimumSunsetNoticeDays": 90
        }
      }
    }
  },
  "components": {
    "headers": {
      "Deprecation": {
        "description": "Present only after this API version receives a formal deprecation date. RFC 9745 structured date such as @1788134400.",
        "schema": {
          "type": "string",
          "pattern": "^@[0-9]+$"
        }
      },
      "Sunset": {
        "description": "Present only for a deprecated version with a scheduled shutdown. RFC 8594 HTTP-date value.",
        "schema": {
          "type": "string"
        }
      },
      "Link": {
        "description": "Links to the public API lifecycle policy with rel=deprecation.",
        "schema": {
          "type": "string"
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Optional caller-generated request correlation key. Batch lookup is side-effect free and returns the same result for the same recordIds.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        }
      }
    },
    "schemas": {
      "RecordStatus": {
        "type": "string",
        "enum": [
          "public",
          "assigned-no-public-record"
        ]
      },
      "CveRecord": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "project",
          "status",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^CVE-[0-9]{4}-[0-9]+$"
          },
          "project": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/RecordStatus"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "limit",
          "returned",
          "total",
          "nextCursor"
        ],
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "returned": {
            "type": "integer",
            "minimum": 0
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "CveRecordPage": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "lastVerified",
          "records",
          "pagination"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string"
          },
          "lastVerified": {
            "type": "string",
            "format": "date"
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CveRecord"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "BatchRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "recordIds"
        ],
        "properties": {
          "recordIds": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "pattern": "^CVE-[0-9]{4}-[0-9]+$"
            }
          }
        }
      },
      "BatchResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "records",
          "missing"
        ],
        "properties": {
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CveRecord"
            }
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Health": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status",
          "version",
          "readOnly",
          "assessmentExecution"
        ],
        "properties": {
          "status": {
            "type": "string",
            "const": "ok"
          },
          "version": {
            "type": "string"
          },
          "readOnly": {
            "type": "boolean",
            "const": true
          },
          "assessmentExecution": {
            "type": "boolean",
            "const": false
          }
        }
      },
      "Sandbox": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "mode",
          "persistent",
          "productionData",
          "authentication",
          "readOnly",
          "capabilities",
          "boundaries",
          "links",
          "exampleRequests"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "mode": {
            "type": "string",
            "const": "sandbox"
          },
          "persistent": {
            "type": "boolean",
            "const": false
          },
          "productionData": {
            "type": "boolean",
            "const": false
          },
          "authentication": {
            "type": "string",
            "const": "none"
          },
          "readOnly": {
            "type": "boolean",
            "const": true
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "boundaries": {
            "type": "object",
            "additionalProperties": true
          },
          "links": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          },
          "exampleRequests": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Capabilities": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "name",
          "version",
          "access",
          "authentication",
          "readOnly",
          "capabilities",
          "boundaries",
          "links"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "access": {
            "type": "string",
            "const": "public"
          },
          "authentication": {
            "type": "string",
            "const": "none"
          },
          "readOnly": {
            "type": "boolean",
            "const": true
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "boundaries": {
            "type": "object",
            "additionalProperties": true
          },
          "links": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          }
        }
      },
      "NlwebResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "url",
          "name",
          "site",
          "score",
          "snippet"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "name": {
            "type": "string"
          },
          "site": {
            "type": "string"
          },
          "score": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "snippet": {
            "type": "string"
          }
        }
      },
      "NlwebResponse": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "query_id",
          "results"
        ],
        "properties": {
          "query_id": {
            "type": "string"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NlwebResult"
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "error",
          "requestId"
        ],
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            }
          },
          "requestId": {
            "type": "string"
          }
        }
      }
    }
  }
}
