{
  "openapi": "3.1.0",
  "info": {
    "title": "Polarity Keystone REST API",
    "description": "Polarity Keystone runs each AI agent task inside an isolated Docker sandbox preloaded with real backing services (Postgres, Redis, S3, internal APIs), scores runs against behavioral invariants and forbidden rules, runs replicas to measure non-determinism, and ships every failure with a seed reproducer.\n\nThis is the public REST API surface. Full documentation: https://docs.polarity.so/keystone/rest-api.",
    "version": "1.0.0",
    "contact": {
      "name": "Polarity Support",
      "url": "https://polarity.so/contact",
      "email": "support@polarity.cc"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://polarity.so/terms-of-service"
    },
    "termsOfService": "https://polarity.so/terms-of-service"
  },
  "servers": [
    {
      "url": "https://keystone.polarity.so/v1",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "Health", "description": "Service health probes" },
    { "name": "Sandboxes", "description": "Isolated Docker sandbox lifecycle" },
    { "name": "Runs", "description": "Agent task runs inside a sandbox" },
    { "name": "Replicas", "description": "Replica suites for non-determinism measurement" },
    { "name": "Specs", "description": "YAML test specifications" },
    { "name": "Scoring", "description": "Behavioral invariants and forbidden rules" }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API key",
        "description": "Polarity uses API keys passed as a bearer token in the Authorization header. Generate keys from the Keystone dashboard. Reads are rate-limited to 100 req/s per key; writes to 10 req/s. Use the Idempotency-Key header to make POSTs safely retryable."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "description": "Client-generated UUID that makes a POST safely retryable. The server stores the response for 24 hours and returns the same result on retry.",
        "required": false,
        "schema": { "type": "string", "format": "uuid" }
      },
      "RequestId": {
        "name": "X-Request-ID",
        "in": "header",
        "description": "Client-supplied trace identifier echoed back on the response. If omitted, the server generates one.",
        "required": false,
        "schema": { "type": "string" }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Request body or parameters failed validation.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": "invalid_request",
              "message": "Field 'spec_id' is required.",
              "request_id": "req_01J7N0E2T8V5GZ"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": "unauthorized",
              "message": "Missing Authorization: Bearer <api_key> header.",
              "request_id": "req_01J7N0E2T8V5GZ"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": "not_found",
              "message": "Sandbox sbx_unknown does not exist.",
              "request_id": "req_01J7N0E2T8V5GZ"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Reads are limited to 100 req/s per key; writes to 10 req/s. Retry after the duration in the Retry-After header.",
        "headers": {
          "Retry-After": {
            "schema": { "type": "integer" },
            "description": "Seconds to wait before retrying."
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": "rate_limited",
              "message": "Write rate limit exceeded. Retry after 2s.",
              "request_id": "req_01J7N0E2T8V5GZ"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error", "message"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable machine-readable error code.",
            "example": "invariant_violation"
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation.",
            "example": "Agent attempted a forbidden tool call: payments.refund"
          },
          "request_id": {
            "type": "string",
            "description": "Echoed trace identifier."
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional structured detail payload — schema depends on the error code."
          }
        }
      },
      "Sandbox": {
        "type": "object",
        "required": ["id", "status", "created_at"],
        "properties": {
          "id": { "type": "string", "example": "sbx_01J7N0E2T8V5GZ" },
          "status": {
            "type": "string",
            "enum": ["provisioning", "ready", "running", "stopped", "failed"],
            "example": "ready"
          },
          "image": { "type": "string", "example": "polarity/keystone-base:v1.4.2" },
          "services": {
            "type": "array",
            "items": { "type": "string" },
            "example": ["postgres", "redis", "s3"]
          },
          "seed": {
            "type": "string",
            "description": "Deterministic seed for this sandbox. Use with /runs/{id}/replay to reproduce.",
            "example": "seed_e3a91b2f"
          },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Run": {
        "type": "object",
        "required": ["id", "sandbox_id", "status", "created_at"],
        "properties": {
          "id": { "type": "string", "example": "run_01J7N0E2T8V5GZ" },
          "sandbox_id": { "type": "string", "example": "sbx_01J7N0E2T8V5GZ" },
          "spec_id": { "type": "string", "example": "spec_refund_v3" },
          "status": {
            "type": "string",
            "enum": ["queued", "running", "passed", "failed", "errored"]
          },
          "score": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "example": 0.94
          },
          "invariant_results": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/InvariantResult" }
          },
          "trajectory_url": {
            "type": "string",
            "format": "uri",
            "description": "Signed URL to the full trajectory JSON for this run."
          },
          "seed": { "type": "string", "example": "seed_e3a91b2f" },
          "duration_ms": { "type": "integer", "example": 12480 },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "InvariantResult": {
        "type": "object",
        "required": ["invariant_id", "status"],
        "properties": {
          "invariant_id": { "type": "string", "example": "inv_no_refund_over_100" },
          "name": { "type": "string", "example": "No refund over $100" },
          "status": { "type": "string", "enum": ["passed", "failed", "skipped"] },
          "evidence": {
            "type": "object",
            "additionalProperties": true,
            "description": "Structured evidence: tool calls observed, values seen, etc."
          }
        }
      },
      "ReplicaSuite": {
        "type": "object",
        "required": ["id", "run_id", "n_replicas", "status"],
        "properties": {
          "id": { "type": "string", "example": "rep_01J7N0E2T8V5GZ" },
          "run_id": { "type": "string", "example": "run_01J7N0E2T8V5GZ" },
          "n_replicas": { "type": "integer", "minimum": 1, "maximum": 1000, "example": 50 },
          "status": { "type": "string", "enum": ["running", "complete", "errored"] },
          "passed": { "type": "integer", "example": 47 },
          "failed": { "type": "integer", "example": 3 },
          "failure_rate": { "type": "number", "format": "float", "example": 0.06 },
          "seeds": {
            "type": "array",
            "items": { "type": "string" },
            "description": "One seed per replica. Use any seed with /runs to reproduce that replica locally."
          }
        }
      },
      "Spec": {
        "type": "object",
        "required": ["id", "name", "yaml"],
        "properties": {
          "id": { "type": "string", "example": "spec_refund_v3" },
          "name": { "type": "string", "example": "Refund agent" },
          "yaml": {
            "type": "string",
            "description": "The raw Keystone YAML spec defining the agent task, sandbox services, invariants, and forbidden rules."
          },
          "created_at": { "type": "string", "format": "date-time" }
        }
      }
    }
  },
  "security": [{ "ApiKeyAuth": [] }],
  "paths": {
    "/health": {
      "get": {
        "tags": ["Health"],
        "summary": "Health probe",
        "description": "Returns 200 if the API is reachable. Useful for agents to probe before making real calls.",
        "security": [],
        "operationId": "getHealth",
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "version": { "type": "string", "example": "v1.4.2" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/sandboxes": {
      "post": {
        "tags": ["Sandboxes"],
        "summary": "Create a sandbox",
        "description": "Spin up an isolated Docker sandbox preloaded with the requested backing services. Returns a sandbox ID and a deterministic seed.",
        "operationId": "createSandbox",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" },
          { "$ref": "#/components/parameters/RequestId" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["image"],
                "properties": {
                  "image": {
                    "type": "string",
                    "description": "Sandbox base image. Defaults to keystone-base.",
                    "example": "polarity/keystone-base:v1.4.2"
                  },
                  "services": {
                    "type": "array",
                    "items": { "type": "string" },
                    "example": ["postgres", "redis", "s3"]
                  },
                  "seed": {
                    "type": "string",
                    "description": "Optional. Reuse a previous seed to reproduce a sandbox exactly.",
                    "example": "seed_e3a91b2f"
                  }
                }
              },
              "examples": {
                "basic": {
                  "value": {
                    "image": "polarity/keystone-base:v1.4.2",
                    "services": ["postgres", "redis"]
                  }
                },
                "replay": {
                  "value": {
                    "image": "polarity/keystone-base:v1.4.2",
                    "services": ["postgres", "redis", "s3"],
                    "seed": "seed_e3a91b2f"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sandbox created",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Sandbox" } }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/sandboxes/{id}": {
      "get": {
        "tags": ["Sandboxes"],
        "summary": "Get a sandbox",
        "operationId": "getSandbox",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "example": "sbx_01J7N0E2T8V5GZ"
          }
        ],
        "responses": {
          "200": {
            "description": "Sandbox state",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Sandbox" } }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "tags": ["Sandboxes"],
        "summary": "Tear down a sandbox",
        "operationId": "deleteSandbox",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "204": { "description": "Sandbox stopped and resources released" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/runs": {
      "post": {
        "tags": ["Runs"],
        "summary": "Run an agent task",
        "description": "Run an agent task inside a sandbox. The spec defines the task, invariants, and forbidden rules. Returns the run ID; poll GET /runs/{id} or subscribe to a webhook for the result.",
        "operationId": "createRun",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" },
          { "$ref": "#/components/parameters/RequestId" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["spec_id"],
                "properties": {
                  "spec_id": { "type": "string", "example": "spec_refund_v3" },
                  "sandbox_id": {
                    "type": "string",
                    "description": "Optional. If omitted, a fresh sandbox is provisioned from the spec.",
                    "example": "sbx_01J7N0E2T8V5GZ"
                  },
                  "seed": {
                    "type": "string",
                    "description": "Optional. Replay a specific seed to reproduce a prior run.",
                    "example": "seed_e3a91b2f"
                  },
                  "inputs": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Free-form inputs that the spec references."
                  }
                }
              },
              "examples": {
                "fresh": {
                  "value": {
                    "spec_id": "spec_refund_v3",
                    "inputs": { "customer_id": "cus_123", "amount_cents": 4500 }
                  }
                },
                "replay": {
                  "value": {
                    "spec_id": "spec_refund_v3",
                    "seed": "seed_e3a91b2f"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Run accepted and queued",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Run" } }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/runs/{id}": {
      "get": {
        "tags": ["Runs"],
        "summary": "Get a run",
        "operationId": "getRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Run state and scoring results",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Run" } }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/runs/{id}/replay": {
      "post": {
        "tags": ["Runs"],
        "summary": "Replay a run from its seed",
        "description": "Re-run the identical sandbox locally using the seed captured from a prior run.",
        "operationId": "replayRun",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "responses": {
          "202": {
            "description": "Replay queued",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Run" } }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/replicas": {
      "post": {
        "tags": ["Replicas"],
        "summary": "Run a replica suite",
        "description": "Run N replicas of the same agent task across fresh sandboxes to measure non-determinism. Returns the suite ID and per-replica seeds.",
        "operationId": "createReplicaSuite",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["spec_id", "n_replicas"],
                "properties": {
                  "spec_id": { "type": "string", "example": "spec_refund_v3" },
                  "n_replicas": { "type": "integer", "minimum": 2, "maximum": 1000, "example": 50 },
                  "inputs": { "type": "object", "additionalProperties": true }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Suite queued",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ReplicaSuite" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/runs/{id}/stream": {
      "get": {
        "tags": ["Runs"],
        "summary": "Stream run events via Server-Sent Events",
        "description": "Open a Server-Sent Events (SSE) stream of live run events: trajectory steps, tool calls, invariant pass/fail, and the terminal `done` event. Returns `text/event-stream`. Each event is a single JSON object on a `data:` line. The stream closes when the run reaches a terminal state or after the configured timeout.",
        "operationId": "streamRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "SSE stream of run events. Each line follows the format `data: {json}\\n\\n`. Event types: `step`, `tool_call`, `invariant_result`, `done`, `error`.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "example": "data: {\"type\":\"step\",\"step\":1,\"action\":\"sql_query\",\"latency_ms\":42}\n\ndata: {\"type\":\"invariant_result\",\"invariant_id\":\"inv_no_refund_over_100\",\"status\":\"passed\"}\n\ndata: {\"type\":\"done\",\"run_id\":\"run_01J7N0E2T8V5GZ\",\"status\":\"passed\",\"score\":0.94}\n\n"
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/replicas/{id}/stream": {
      "get": {
        "tags": ["Replicas"],
        "summary": "Stream replica suite progress via SSE",
        "description": "Server-Sent Events stream of replica completions as they finish, useful for live dashboards of long replica suites.",
        "operationId": "streamReplicaSuite",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "SSE stream of replica events.",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/replicas/{id}": {
      "get": {
        "tags": ["Replicas"],
        "summary": "Get replica suite results",
        "operationId": "getReplicaSuite",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Replica suite state and failure rate",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ReplicaSuite" } }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/specs": {
      "post": {
        "tags": ["Specs"],
        "summary": "Upload a YAML spec",
        "operationId": "createSpec",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "yaml"],
                "properties": {
                  "name": { "type": "string", "example": "Refund agent" },
                  "yaml": {
                    "type": "string",
                    "description": "Raw Keystone YAML spec."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Spec stored",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Spec" } }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/specs/{id}": {
      "get": {
        "tags": ["Specs"],
        "summary": "Get a spec",
        "operationId": "getSpec",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Spec body",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Spec" } }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    }
  },
  "webhooks": {
    "run.completed": {
      "post": {
        "summary": "Fired when an agent run reaches a terminal state",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/Run" }
            }
          }
        },
        "responses": {
          "200": { "description": "Acknowledged" }
        }
      }
    },
    "replica.completed": {
      "post": {
        "summary": "Fired when a replica suite finishes",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ReplicaSuite" }
            }
          }
        },
        "responses": {
          "200": { "description": "Acknowledged" }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Full developer documentation",
    "url": "https://docs.polarity.so/keystone"
  }
}
